日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux I/O 那些事儿

發(fā)布時(shí)間:2024/2/28 linux 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux I/O 那些事儿 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.


介紹 Linux IO 的一些基本原理。

作者:arraywang,騰訊 CSIG

我們先看一張圖:

這張圖大體上描述了 Linux 系統(tǒng)上,應(yīng)用程序?qū)Υ疟P上的文件進(jìn)行讀寫時(shí),從上到下經(jīng)歷了哪些事情。

這篇文章就以這張圖為基礎(chǔ),介紹 Linux 在 I/O 上做了哪些事情。

文件系統(tǒng)

什么是文件系統(tǒng)

文件系統(tǒng),本身是對存儲設(shè)備上的文件,進(jìn)行組織管理的機(jī)制。組織方式不同,就會形成不同的文件系統(tǒng)。比如常見的 Ext4、XFS、ZFS 以及網(wǎng)絡(luò)文件系統(tǒng) NFS 等等。

但是不同類型的文件系統(tǒng)標(biāo)準(zhǔn)和接口可能各有差異,我們在做應(yīng)用開發(fā)的時(shí)候卻很少關(guān)心系統(tǒng)調(diào)用以下的具體實(shí)現(xiàn),大部分時(shí)候都是直接系統(tǒng)調(diào)用 open, read, write, close 來實(shí)現(xiàn)應(yīng)用程序的功能,不會再去關(guān)注我們具體用了什么文件系統(tǒng)(UFS、XFS、Ext4、ZFS),磁盤是什么接口(IDE、SCSI,SAS,SATA 等),磁盤是什么存儲介質(zhì)(HDD、SSD)

應(yīng)用開發(fā)者之所以這么爽,各種復(fù)雜細(xì)節(jié)都不用管直接調(diào)接口,是因?yàn)閮?nèi)核為我們做了大量的有技術(shù)含量的臟活累活。開始的那張圖看到 Linux 在各種不同的文件系統(tǒng)之上,虛擬了一個(gè) VFS,目的就是統(tǒng)一各種不同文件系統(tǒng)的標(biāo)準(zhǔn)和接口,讓開發(fā)者可以使用相同的系統(tǒng)調(diào)用來使用不同的文件系統(tǒng)。

文件系統(tǒng)如何工作(VFS)

Linux 系統(tǒng)下的文件

在 Linux 中一切皆文件。不僅普通的文件和目錄,就連塊設(shè)備、套接字、管道等,也都要通過統(tǒng)一的文件系統(tǒng)來管理。

用?ls?-l?命令看最前面的字符可以看到這個(gè)文件是什么類型brw-r--r--?1?root????root????1,?2?4月??25?11:03?bnod?//?塊設(shè)備文件 crw-r--r--?1?root????root????1,?2?4月??25?11:04?cnod?//?符號設(shè)備文件 drwxr-xr-x?2?wrn3552?wrn3552????6?4月??25?11:01?dir?//?目錄 -rw-r--r--?1?wrn3552?wrn3552????0?4月??25?11:01?file?//?普通文件 prw-r--r--?1?root????root???????0?4月??25?11:04?pipeline?//?有名管道 srwxr-xr-x?1?root????root???????0?4月??25?11:06?socket.sock?//?socket文件 lrwxrwxrwx?1?root????root???????4?4月??25?11:04?softlink?->?file?//?軟連接 -rw-r--r--?2?wrn3552?wrn3552?0?4月??25?11:07?hardlink?//?硬鏈接(本質(zhì)也是普通文件)

Linux 文件系統(tǒng)設(shè)計(jì)了兩個(gè)數(shù)據(jù)結(jié)構(gòu)來管理這些不同種類的文件:

  • inode(index node):索引節(jié)點(diǎn)

  • dentry(directory entry):目錄項(xiàng)

inode 和 dentry

inode

inode 是用來記錄文件的 metadata,所謂 metadata 在 Wikipedia 上的描述是 data of data,其實(shí)指的就是文件的各種屬性,比如 inode 編號、文件大小、訪問權(quán)限、修改日期、數(shù)據(jù)的位置等。

wrn3552@novadev:~/playground$?stat?file文件:file大小:0???????????????塊:0????????? IO 塊:4096 ??普通空文件 設(shè)備:fe21h/65057d ???? Inode:32828 ??????硬鏈接:2 權(quán)限:(0644/-rw-r--r--)? Uid:( 3041/ wrn3552)?? Gid:( 3041/ wrn3552) 最近訪問:2021-04-25 11:07:59.603745534 +0800 最近更改:2021-04-25 11:07:59.603745534 +0800 最近改動:2021-04-25 11:08:04.739848692 +0800 創(chuàng)建時(shí)間:-

inode 和文件一一對應(yīng),它跟文件內(nèi)容一樣,都會被持久化存儲到磁盤中。所以,inode 同樣占用磁盤空間,只不過相對于文件來說它大小固定且大小不算大。

dentry

dentry 用來記錄文件的名字、inode 指針以及與其他 dentry 的關(guān)聯(lián)關(guān)系。

wrn3552@novadev:~/playground$?tree . ├──?dir │???└──?file_in_dir ├──?file └──?hardlink
  • 文件的名字:像 dir、file、hardlink、file_in_dir 這些名字是記錄在 dentry 里的

  • inode 指針:就是指向這個(gè)文件的 inode

  • 與其他 dentry 的關(guān)聯(lián)關(guān)系:其實(shí)就是每個(gè)文件的層級關(guān)系,哪個(gè)文件在哪個(gè)文件下面,構(gòu)成了文件系統(tǒng)的目錄結(jié)構(gòu)

不同于 inode,dentry 是由內(nèi)核維護(hù)的一個(gè)內(nèi)存數(shù)據(jù)結(jié)構(gòu),所以通常也被叫做 dentry cache。

文件是如何存儲在磁盤上的

這里有張圖解釋了文件是如何存儲在磁盤上的,首先,磁盤再進(jìn)行文件系統(tǒng)格式化的時(shí)候,會分出來 3 個(gè)區(qū):

  • Superblock

  • inode blocks

  • data blocks

  • (其實(shí)還有 boot block,可能會包含一些 bootstrap 代碼,在機(jī)器啟動的時(shí)候被讀到,這里忽略)其中 inode blocks 放的都是每個(gè)文件的 inode,data blocks 里放的是每個(gè)文件的內(nèi)容數(shù)據(jù)。這里關(guān)注一下 superblock,它包含了整個(gè)文件系統(tǒng)的 metadata,具體有:

  • inode/data block 總量、使用量、剩余量

  • 文件系統(tǒng)的格式,屬主等等各種屬性

  • superblock 對于文件系統(tǒng)來說非常重要,如果 superblock 損壞了,文件系統(tǒng)就掛載不了了,相應(yīng)的文件也沒辦法讀寫。既然 superblock 這么重要,那肯定不能只有一份,壞了就沒了,它在系統(tǒng)中是有很多副本的,在 superblock 損壞的時(shí)候,可以使用 fsck(File System Check and repair)來恢復(fù)。回到上面的那張圖,可以很清晰地看到文件的各種屬性和文件的數(shù)據(jù)是如何存儲在磁盤上的:

  • dentry 里包含了文件的名字、目錄結(jié)構(gòu)、inode 指針

  • inode 指針指向文件特定的 inode(存在 inode blocks 里)

  • 每個(gè) inode 又指向 data blocks 里具體的 logical block,這里的 logical block 存的就是文件具體的數(shù)據(jù)

  • 這里解釋一下什么是 logical block:

  • 對于不同存儲介質(zhì)的磁盤,都有最小的讀寫單元

    • /sys/block/sda/queue/physical_block_size

  • HDD 叫做 sector(扇區(qū)),SSD 叫做 page(頁面)

  • 對于 hdd 來說,每個(gè) sector 大小 512Bytes

  • 對于 SSD 來說每個(gè) page 大小不等(和 cell 類型有關(guān)),經(jīng)典的大小是 4KB

  • 但是 Linux 覺得按照存儲介質(zhì)的最小讀寫單元來進(jìn)行讀寫可能會有效率問題,所以支持在文件系統(tǒng)格式化的時(shí)候指定 block size 的大小,一般是把幾個(gè) physical_block 拼起來就成了一個(gè) logical block

    • /sys/block/sda/queue/logical_block_size

  • 理論上應(yīng)該是 logical_block_size >= physical_block_size,但是有時(shí)候我們會看到 physical_block_size = 4K,logical_block_size = 512B 情況,其實(shí)這是因?yàn)榇疟P上做了一層 512B 的仿真(emulation)(詳情可參考 512e 和 4Kn)

  • ZFS

    這里簡單介紹一個(gè)廣泛應(yīng)用的文件系統(tǒng) ZFS,一些數(shù)據(jù)庫應(yīng)用也會用到 ZFS,先看一張 zfs 的層級結(jié)構(gòu)圖:

    這是一張從底向上的圖:

  • 將若干物理設(shè)備 disk 組成一個(gè)虛擬設(shè)備 vdev(同時(shí),disk 也是一種 vdev)

  • 再將若干個(gè)虛擬設(shè)備 vdev 加到一個(gè) zpool 里

  • 在 zpool 的基礎(chǔ)上創(chuàng)建 zfs 并掛載(zvol 可以先不看,我們沒有用到)

  • ZFS 的一些操作

    創(chuàng)建 zpool

    root@:~?#?zpool?create?tank?raidz?/dev/ada1?/dev/ada2?/dev/ada3?raidz?/dev/ada4?/dev/ada5?/dev/ada6 root@:~?#?zpool?list?tank NAME????SIZE??ALLOC???FREE??CKPOINT??EXPANDSZ???FRAG????CAP??DEDUP??HEALTH??ALTROOT tank?????11G???824K??11.0G????????-?????????-?????0%?????0%??1.00x??ONLINE??- root@:~?#?zpool?status?tankpool:?tankstate:?ONLINEscan:?none?requested config:NAME????????STATE?????READ?WRITE?CKSUMtank????????ONLINE???????0?????0?????0raidz1-0??ONLINE???????0?????0?????0ada1????ONLINE???????0?????0?????0ada2????ONLINE???????0?????0?????0ada3????ONLINE???????0?????0?????0raidz1-1??ONLINE???????0?????0?????0ada4????ONLINE???????0?????0?????0ada5????ONLINE???????0?????0?????0ada6????ONLINE???????0?????0?????0
    • 創(chuàng)建了一個(gè)名為 tank 的 zpool

    • 這里的 raidz 同 RAID5

    除了 raidz 還支持其他方案:

    創(chuàng)建 zfs

    root@:~?#?zfs?create?-o?mountpoint=/mnt/srev?tank/srev root@:~?#?df?-h?tank/srev Filesystem????Size????Used???Avail?Capacity??Mounted?on tank/srev?????7.1G????117K????7.1G?????0%????/mnt/srev
    • 創(chuàng)建了一個(gè) zfs,掛載到了 /mnt/srev

    • 這里沒有指定 zfs 的 quota,創(chuàng)建的 zfs 大小即 zpool 大小

    對 zfs 設(shè)置 quota

    root@:~?#?zfs?set?quota=1G?tank/srev root@:~?#?df?-h?tank/srev Filesystem????Size????Used???Avail?Capacity??Mounted?on tank/srev?????1.0G????118K????1.0G?????0%????/mnt/srev

    ZFS 特性

    Pool 存儲

    上面的層級圖和操作步驟可以看到 zfs 是基于 zpool 創(chuàng)建的,zpool 可以動態(tài)擴(kuò)容意味著存儲空間也可以動態(tài)擴(kuò)容,而且可以創(chuàng)建多個(gè)文件系統(tǒng),文件系統(tǒng)共享完整的 zpool 空間無需預(yù)分配。

    事務(wù)文件系統(tǒng)

    zfs 的寫操作是事務(wù)的,意味著要么就沒寫,要么就寫成功了,不會像其他文件系統(tǒng)那樣,應(yīng)用打開了文件,寫入還沒保存的時(shí)候斷電,導(dǎo)致文件為空。zfs 保證寫操作事務(wù)采用的是 copy on write 的方式:

    • 當(dāng) block B 有修改變成 B1 的時(shí)候,普通的文件系統(tǒng)會直接在 block B 原地進(jìn)行修改變成 B1

    • zfs 則會再另一個(gè)地方寫 B1,然后再在后面安全的時(shí)候?qū)υ瓉淼?B 進(jìn)行回收

    • 這樣結(jié)果就不會出現(xiàn) B 被打開而寫失敗的情況,大不了就是 B1 沒寫成功

    這個(gè)特性讓 zfs 在斷電后不需要執(zhí)行 fsck 來檢查磁盤中是否存在寫操作失敗需要恢復(fù)的情況,大大提升了應(yīng)用的可用性。

    ARC 緩存

    ZFS 中的 ARC(Adjustable Replacement Cache) 讀緩存淘汰算法,是基于 IBM 的 ARP(Adaptive Replacement Cache) 演化而來。在一些文件系統(tǒng)中實(shí)現(xiàn)的標(biāo)準(zhǔn) LRU 算法其實(shí)是有缺陷的:比如復(fù)制大文件之類的線性大量 I/O 操作,導(dǎo)致緩存失效率猛增(大量文件只讀一次,放到內(nèi)存不會被再讀,坐等淘汰)。

    另外,緩存可以根據(jù)時(shí)間來進(jìn)行優(yōu)化(LRU,最近最多使用),也可以根據(jù)頻率進(jìn)行優(yōu)化(LFU,最近最常使用),這兩種方法各有優(yōu)劣,但是沒辦法適應(yīng)所有場景。

    ARC 的設(shè)計(jì)就是嘗試在 LRU 和 LFU 之間找到一個(gè)平衡,根據(jù)當(dāng)前的 I/O workload 來調(diào)整用 LRU 多一點(diǎn)還是 LFU 多一點(diǎn)。

    ARC 定義了 4 個(gè)鏈表:

  • LRU list:最近最多使用的頁面,存具體數(shù)據(jù)

  • LFU list:最近最常使用的頁面,存具體數(shù)據(jù)

  • Ghost list for LRU:最近從 LRU 表淘汰下來的頁面信息,不存具體數(shù)據(jù),只存頁面信息

  • Ghost list for LFU:最近從 LFU 表淘汰下來的頁面信息,不存具體數(shù)據(jù),只存頁面信息

  • ARC 工作流程大致如下:

  • LRU list 和 LFU list 填充和淘汰過程和標(biāo)準(zhǔn)算法一樣

  • 當(dāng)一個(gè)頁面從 LRU list 淘汰下來時(shí),這個(gè)頁面的信息會放到 LRU ghost 表中

  • 如果這個(gè)頁面一直沒被再次引用到,那么這個(gè)頁面的信息最終也會在 LRU ghost 表中被淘汰掉

  • 如果這個(gè)頁面在 LRU ghost 表中未被淘汰的時(shí)候,被再一次訪問了,這時(shí)候會引起一次幽靈(phantom)命中

  • phantom 命中的時(shí)候,事實(shí)上還是要把數(shù)據(jù)從磁盤第一次放緩存

  • 但是這時(shí)候系統(tǒng)知道剛剛被 LRU 表淘汰的頁面又被訪問到了,說明 LRU list 太小了,這時(shí)它會把 LRU list 長度加一,LFU 長度減一

  • 對于 LFU 的過程也與上述過程類似

  • ZFS 參考資料

    關(guān)于 ZFS 詳細(xì)介紹可以參考:

    • 這篇文章

    磁盤類型

    磁盤根據(jù)不同的分類方式,有各種不一樣的類型。

    磁盤的存儲介質(zhì)

    根據(jù)磁盤的存儲介質(zhì)可以分兩類(大家都很熟悉):

    • HDD(機(jī)械硬盤)

    • SSD(固態(tài)硬盤)

    磁盤的接口

    根據(jù)磁盤接口分類:

    • IDE (Integrated Drive Electronics)

    • SCSI (Small Computer System Interface)

    • SAS (Serial Attached SCSI)

    • SATA (Serial ATA)

    • ...

    不同的接口,往往分配不同的設(shè)備名稱。比如, IDE 設(shè)備會分配一個(gè) hd 前綴的設(shè)備名,SCSI 和 SATA 設(shè)備會分配一個(gè) sd 前綴的設(shè)備名。如果是多塊同類型的磁盤,就會按照 a、b、c 等的字母順序來編號。

    Linux 對磁盤的管理

    其實(shí)在 Linux 中,磁盤實(shí)際上是作為一個(gè)塊設(shè)備來管理的,也就是以塊為單位讀寫數(shù)據(jù),并且支持隨機(jī)讀寫。每個(gè)塊設(shè)備都會被賦予兩個(gè)設(shè)備號,分別是主、次設(shè)備號。主設(shè)備號用在驅(qū)動程序中,用來區(qū)分設(shè)備類型;而次設(shè)備號則是用來給多個(gè)同類設(shè)備編號。

    g18-"299"?on?~#?ls?-l?/dev/sda* brw-rw----?1?root?disk?8,??0?Apr?25?15:53?/dev/sda brw-rw----?1?root?disk?8,??1?Apr?25?15:53?/dev/sda1 brw-rw----?1?root?disk?8,?10?Apr?25?15:53?/dev/sda10 brw-rw----?1?root?disk?8,??2?Apr?25?15:53?/dev/sda2 brw-rw----?1?root?disk?8,??5?Apr?25?15:53?/dev/sda5 brw-rw----?1?root?disk?8,??6?Apr?25?15:53?/dev/sda6 brw-rw----?1?root?disk?8,??7?Apr?25?15:53?/dev/sda7 brw-rw----?1?root?disk?8,??8?Apr?25?15:53?/dev/sda8 brw-rw----?1?root?disk?8,??9?Apr?25?15:53?/dev/sda9
    • 這些 sda 磁盤主設(shè)備號都是 8,表示它是一個(gè) sd 類型的塊設(shè)備

    • 次設(shè)備號 0-10 表示這些不同 sd 塊設(shè)備的編號

    Generic Block Layer

    和 VFS 類似,為了對上層屏蔽不同塊設(shè)備的差異,內(nèi)核在文件系統(tǒng)和塊設(shè)備之前抽象了一個(gè) Generic Block Layer(通用塊層),有時(shí)候一些人也會把下面的 I/O 調(diào)度層并到通用塊層里表述。

    這兩層主要做兩件事:

  • 跟 VFS 的功能類似。向上,為文件系統(tǒng)和應(yīng)用程序,提供訪問塊設(shè)備的標(biāo)準(zhǔn)接口;向下,把各種異構(gòu)的磁盤設(shè)備抽象為統(tǒng)一的塊設(shè)備,并提供統(tǒng)一框架來管理這些設(shè)備的驅(qū)動程序

  • 對 I/O 請求進(jìn)行調(diào)度,通過重新排序、合并等方式,提高磁盤讀寫效率

  • 下圖是一個(gè)完整的 I/O 棧全景圖:

    可以看到中間的 Block Layer 其實(shí)就是 Generic Block Layer,在圖中可以看到 Block Layer 的 I/O 調(diào)度分為兩類,分別表示單隊(duì)列和多隊(duì)列的調(diào)度:

    • I/O scheduler

    • blkmq

    I/O 調(diào)度

    老版本的內(nèi)核里只支持單隊(duì)列的 I/O scheduler,在 3.16 版本的內(nèi)核開始支持多隊(duì)列 blkmq,這里介紹幾種經(jīng)典的 I/O 調(diào)度策略。

    單隊(duì)列 I/O scheduler:

    • NOOP:事實(shí)上是個(gè) FIFO 的隊(duì)列,只做基本的請求合并

    • CFQ:Completely Fair Queueing,完全公平調(diào)度器,給每個(gè)進(jìn)程維護(hù)一個(gè) I/O 調(diào)度隊(duì)列,按照時(shí)間片來均勻分布每個(gè)進(jìn)程 I/O 請求,

    • DeadLine:為讀和寫請求創(chuàng)建不同的 I/O 隊(duì)列,確保達(dá)到 deadline 的請求被優(yōu)先處理

    多隊(duì)列 blkmq:

    • bfq:Budget Fair Queueing,也是公平調(diào)度器,不過不是按時(shí)間片來分配,而是按請求的扇區(qū)數(shù)量(帶寬)

    • kyber:維護(hù)兩個(gè)隊(duì)列(同步/讀、異步/寫),同時(shí)嚴(yán)格限制發(fā)到這兩個(gè)隊(duì)列的請求數(shù)以保證相應(yīng)時(shí)間

    • mq-deadline:多隊(duì)列版本的 deadline

    • 具體各種 I/O 調(diào)度策略可以參考 IOSchedulers

    • 關(guān)于 blkmq 可以參考 Linux Multi-Queue Block IO Queueing Mechanism (blk-mq) Details

    • 多隊(duì)列調(diào)度可以參考 Block layer introduction part 2: the request layer

    性能指標(biāo)

    一般來說 I/O 性能指標(biāo)有這幾個(gè):

    • 使用率:ioutil,指的是磁盤處理 I/O 的時(shí)間百分比,ioutil 只看有沒有 I/O 請求,不看 I/O 請求的大小。ioutil 越高表示一直都有 I/O 請求,不代表磁盤無法響應(yīng)新的 I/O 請求

    • IOPS:每秒的 I/O 請求數(shù)

    • 吞吐量/帶寬:每秒的 I/O 請求大小,通常是 MB/s 或者 GB/s 為單位

    • 響應(yīng)時(shí)間:I/O 請求發(fā)出到收到響應(yīng)的時(shí)間

    • 飽和度:指的是磁盤處理 I/O 的繁忙程度。這個(gè)指標(biāo)比較玄學(xué),沒有直接的數(shù)據(jù)可以表示,一般是根據(jù)平均隊(duì)列請求長度或者響應(yīng)時(shí)間跟基準(zhǔn)測試的結(jié)果進(jìn)行對比來估算

    (在做基準(zhǔn)測試時(shí),還會分順序/隨機(jī)、讀/寫進(jìn)行排列組合分別去測 IOPS 和帶寬)

    上面的指標(biāo)除了飽和度外,其他都可以在監(jiān)控系統(tǒng)中看到。Linux 也提供了一些命令來輸出不同維度的 I/O 狀態(tài):

    • iostat -d -x:看各個(gè)設(shè)備的 I/O 狀態(tài),數(shù)據(jù)來源 /proc/diskstats

    • pidstat -d:看近處的 I/O

    • iotop:類似 top,按 I/O 大小對進(jìn)程排序

    超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的Linux I/O 那些事儿的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。