<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你不好奇Linux文件系統(tǒng)是怎么工作的?

          共 14385字,需瀏覽 29分鐘

           ·

          2021-09-03 08:31

          關(guān)注「開源Linux」,選擇“設(shè)為星標(biāo)”
          回復(fù)「學(xué)習(xí)」,有我為您特別篩選的學(xué)習(xí)資料~

          1前言

          和 CPU、內(nèi)存一樣,磁盤和文件系統(tǒng)的管理也是操作系統(tǒng)最核心的功能。

          磁盤為系統(tǒng)提供了最基本的持久化存儲。文件系統(tǒng)則在磁盤的基礎(chǔ)上,提供了一個用來管理文件的樹狀結(jié)構(gòu)。那么,磁盤和文件系統(tǒng)是怎么工作的呢?又有哪些指標(biāo)可以衡量它們的性能呢?

          2索引節(jié)點和目錄項

          文件系統(tǒng)本身是對存儲設(shè)備上的文件進(jìn)行組織管理的機制。組織方式不同就會形成不同的文件系統(tǒng)。

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

          為了方便管理,Linux 文件系統(tǒng)為每個文件都分配兩個數(shù)據(jù)結(jié)構(gòu),索引節(jié)點(index node)和目錄項(directory entry)。它們主要用來記錄文件的元信息和目錄結(jié)構(gòu)。

          • 索引節(jié)點,簡稱為 inode,用來記錄文件的元數(shù)據(jù),比如 inode 編號、文件大小、訪問 權(quán)限、修改日期、數(shù)據(jù)的位置等。索引節(jié)點和文件一一對應(yīng),它跟文件內(nèi)容一樣,都會 被持久化存儲到磁盤中。所以記住,索引節(jié)點同樣占用磁盤空間。

          • 目錄項,簡稱為 dentry,用來記錄文件的名字、索引節(jié)點指針以及與其他目錄項的關(guān)聯(lián) 關(guān)系。多個關(guān)聯(lián)的目錄項,就構(gòu)成了文件系統(tǒng)的目錄結(jié)構(gòu)。不過,不同于索引節(jié)點,目錄項是由內(nèi)核維護(hù)的一個內(nèi)存數(shù)據(jù)結(jié)構(gòu),所以通常也被叫做目錄項緩存。

          換句話說,索引節(jié)點是每個文件的唯一標(biāo)志,而目錄項維護(hù)的正是文件系統(tǒng)的樹狀結(jié)構(gòu)。目錄項和索引節(jié)點的關(guān)系是多對一,你可以簡單理解為,一個文件可以有多個別名。

          舉個例子,通過硬鏈接為文件創(chuàng)建的別名,就會對應(yīng)不同的目錄項,不過這些目錄項本質(zhì)上還是鏈接同一個文件,所以,它們的索引節(jié)點相同。

          索引節(jié)點和目錄項記錄了文件的元數(shù)據(jù),以及文件間的目錄關(guān)系,那么具體來說,文件數(shù)據(jù)到底是怎么存儲的呢?是不是直接寫到磁盤中就好了呢?

          實際上,磁盤讀寫的最小單位是扇區(qū),然而扇區(qū)只有 512B 大小,如果每次都讀寫這么小的單位,效率一定很低。所以,文件系統(tǒng)又把連續(xù)的扇區(qū)組成了邏輯塊,然后每次都以邏 輯塊為最小單元,來管理數(shù)據(jù)。常見的邏輯塊大小為 4KB,也就是由連續(xù)的 8 個扇區(qū)組成。

          為了幫助我們理解目錄項、索引節(jié)點以及文件數(shù)據(jù)的關(guān)系,畫了一張示意圖。我們可以對照著這張圖,來回憶剛剛講過的內(nèi)容,把知識和細(xì)節(jié)串聯(lián)起來。

          不過,這里有兩點需要我們注意:

          • 第一,目錄項本身就是一個內(nèi)存緩存,而索引節(jié)點則是存儲在磁盤中的數(shù)據(jù)。在前面的 Buffer 和 Cache 原理中,我曾經(jīng)提到過,為了協(xié)調(diào)慢速磁盤與快速 CPU 的性能差異,文 件內(nèi)容會緩存到頁緩存 Cache 中。那么,我們也應(yīng)該想到,這些索引節(jié)點自然也會緩存到內(nèi)存中,加速文件的訪問。

          • 第二,磁盤在執(zhí)行文件系統(tǒng)格式化時,會被分成三個存儲區(qū)域,超級塊、索引節(jié)點區(qū)和數(shù)據(jù)塊區(qū)。其中:

          超級塊,存儲整個文件系統(tǒng)的狀態(tài)。

          索引節(jié)點區(qū),用來存儲索引節(jié)點。

          數(shù)據(jù)塊區(qū),則用來存儲文件數(shù)據(jù)。

          3虛擬文件系統(tǒng)

          目錄項、索引節(jié)點、邏輯塊以及超級塊,構(gòu)成了 Linux 文件系統(tǒng)的四大基本要素。不過, 為了支持各種不同的文件系統(tǒng),Linux 內(nèi)核在用戶進(jìn)程和文件系統(tǒng)的中間,又引入了一個抽象層,也就是虛擬文件系統(tǒng) VFS(Virtual File System)。

          VFS 定義了一組所有文件系統(tǒng)都支持的數(shù)據(jù)結(jié)構(gòu)和標(biāo)準(zhǔn)接口。這樣,用戶進(jìn)程和內(nèi)核中的其他子系統(tǒng),只需要跟 VFS 提供的統(tǒng)一接口進(jìn)行交互就可以了,而不需要再關(guān)心底層各種文件系統(tǒng)的實現(xiàn)細(xì)節(jié)。

          下圖是 Linux 文件系統(tǒng)的架構(gòu)圖,幫我們更好地理解系統(tǒng)調(diào)用、VFS緩存、文件系統(tǒng)以及塊存儲之間的關(guān)系。

          通過這張圖,可以看到,在 VFS 的下方,Linux 支持各種各樣的文件系統(tǒng),如 Ext4、 XFS、NFS 等等。按照存儲位置的不同,這些文件系統(tǒng)可以分為三類。

          • 第一類是基于磁盤的文件系統(tǒng),也就是把數(shù)據(jù)直接存儲在計算機本地掛載的磁盤中。常見的 Ext4、XFS、OverlayFS 等,都是這類文件系統(tǒng)。

          • 第二類是基于內(nèi)存的文件系統(tǒng),也就是我們常說的虛擬文件系統(tǒng)。這類文件系統(tǒng),不需要任何磁盤分配存儲空間,但會占用內(nèi)存。我們經(jīng)常用到的 /proc 文件系統(tǒng),其實就是 一種最常見的虛擬文件系統(tǒng)。此外,/sys 文件系統(tǒng)也屬于這一類,主要向用戶空間導(dǎo)出層次化的內(nèi)核對象。

          • 第三類是網(wǎng)絡(luò)文件系統(tǒng),也就是用來訪問其他計算機數(shù)據(jù)的文件系統(tǒng),比如 NFS、 SMB、iSCSI 等。

          這些文件系統(tǒng),要先掛載到 VFS 目錄樹中的某個子目錄(稱為掛載點),然后才能訪問其中的文件。拿第一類,也就是基于磁盤的文件系統(tǒng)為例,在安裝系統(tǒng)時,要先掛載一個根 目錄(/),在根目錄下再把其他文件系統(tǒng)(比如其他的磁盤分區(qū)、/proc 文件系統(tǒng)、/sys 文件系統(tǒng)、NFS 等)掛載進(jìn)來。

          4文件系統(tǒng) I/O

          把文件系統(tǒng)掛載到掛載點后,你就能通過掛載點,再去訪問它管理的文件了。VFS 提供了一組標(biāo)準(zhǔn)的文件訪問接口。這些接口以系統(tǒng)調(diào)用的方式,提供給應(yīng)用程序使用。

          就拿 cat 命令來說,它首先調(diào)用 open() ,打開一個文件;然后調(diào)用 read() ,讀取文件的內(nèi)容;最后再調(diào)用 write() ,把文件內(nèi)容輸出到控制臺的標(biāo)準(zhǔn)輸出中:

          int open(const char *pathname, int flags, mode_t mode); 
          ssize_t read(int fd, void *buf, size_t count);
          ssize_t write(int fd, const void *buf, size_t count);

          文件讀寫方式的各種差異,導(dǎo)致 I/O 的分類多種多樣。最常見的有,緩沖與非緩沖 I/O、 直接與非直接 I/O、阻塞與非阻塞 I/O、同步與異步 I/O 等。接下來,我們就詳細(xì)看這四種分類。

          第一種,根據(jù)是否利用標(biāo)準(zhǔn)庫緩存,可以把文件 I/O 分為緩沖 I/O 與非緩沖 I/O。

          • 緩沖 I/O,是指利用標(biāo)準(zhǔn)庫緩存來加速文件的訪問,而標(biāo)準(zhǔn)庫內(nèi)部再通過系統(tǒng)調(diào)度訪問文件。

          • 非緩沖 I/O,是指直接通過系統(tǒng)調(diào)用來訪問文件,不再經(jīng)過標(biāo)準(zhǔn)庫緩存。

          注意,這里所說的“緩沖”,是指標(biāo)準(zhǔn)庫內(nèi)部實現(xiàn)的緩存。比方說,你可能見到過,很多程序遇到換行時才真正輸出,而換行前的內(nèi)容,其實就是被標(biāo)準(zhǔn)庫暫時緩存了起來。

          無論緩沖 I/O 還是非緩沖 I/O,它們最終還是要經(jīng)過系統(tǒng)調(diào)用來訪問文件。我們知道,系統(tǒng)調(diào)用后,還會通過頁緩存,來減少磁盤的 I/O 操作。

          第二,根據(jù)是否利用操作系統(tǒng)的頁緩存,可以把文件 I/O 分為直接 I/O 與非直接 I/O。

          • 直接 I/O,是指跳過操作系統(tǒng)的頁緩存,直接跟文件系統(tǒng)交互來訪問文件。

          • 非直接 I/O 正好相反,文件讀寫時,先要經(jīng)過系統(tǒng)的頁緩存,然后再由內(nèi)核或額外的系統(tǒng)調(diào)用,真正寫入磁盤。

          想要實現(xiàn)直接 I/O,需要你在系統(tǒng)調(diào)用中,指定 O_DIRECT 標(biāo)志。如果沒有設(shè)置過,默認(rèn) 的是非直接 I/O。

          不過要注意,直接 I/O、非直接 I/O,本質(zhì)上還是和文件系統(tǒng)交互。如果是在數(shù)據(jù)庫等場景中,還會看到,跳過文件系統(tǒng)讀寫磁盤的情況,也就是我們通常所說的裸 I/O。

          第三,根據(jù)應(yīng)用程序是否阻塞自身運行,可以把文件 I/O 分為阻塞 I/O 和非阻塞 I/O

          • 所謂阻塞 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,如果沒有獲得響應(yīng),就會阻塞當(dāng)前線程,自然就不能執(zhí)行其他任務(wù)。

          • 所謂非阻塞 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,不會阻塞當(dāng)前的線程,可以繼續(xù)執(zhí)行其他的任務(wù),隨后再通過輪詢或者事件通知的形式,獲取調(diào)用的結(jié)果。

          比方說,訪問管道或者網(wǎng)絡(luò)套接字時,設(shè)置 O_NONBLOCK 標(biāo)志,就表示用非阻塞方式訪問;而如果不做任何設(shè)置,默認(rèn)的就是阻塞訪問。

          第四,根據(jù)是否等待響應(yīng)結(jié)果,可以把文件 I/O 分為同步和異步 I/O

          • 所謂同步 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,要一直等到整個 I/O 完成后,才能獲得 I/O 響應(yīng)。

          • 所謂異步 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,不用等待完成和完成后的響應(yīng),而是繼續(xù)執(zhí)行就可以。等到這次 I/O 完成后,響應(yīng)會用事件通知的方式,告訴應(yīng)用程序。

          例如,在操作文件時,如果設(shè)置了 O_SYNC 或者 O_DSYNC 標(biāo)志,就代表同步 I/O。如果設(shè)置了 O_DSYNC,就要等文件數(shù)據(jù)寫入磁盤后,才能返回;而 O_SYNC,則是在 O_DSYNC 基礎(chǔ)上,要求文件元數(shù)據(jù)也要寫入磁盤后,才能返回。

          再比如,在訪問管道或者網(wǎng)絡(luò)套接字時,設(shè)置了 O_ASYNC 選項后,相應(yīng)的 I/O 就是異步I/O。這樣,內(nèi)核會再通過 SIGIO 或者 SIGPOLL,來通知進(jìn)程文件是否可讀寫。

          我們可能發(fā)現(xiàn)了,這里的好多概念也經(jīng)常出現(xiàn)在網(wǎng)絡(luò)編程中。比如非阻塞 I/O,通常會跟 select/poll 配合,用在網(wǎng)絡(luò)套接字的 I/O 中。

          這下我們也應(yīng)該可以理解,“Linux 一切皆文件”的深刻含義。無論是普通文件和塊設(shè)備、還是網(wǎng)絡(luò)套接字和管道等,它們都通過統(tǒng)一的 VFS 接口來訪問。

          5性能觀測

          接下來,打開一個終端,SSH 登錄到服務(wù)器上,我們一起來探索,如何觀測文件系統(tǒng)的性能。

          容量

          對文件系統(tǒng)來說,最常見的一個問題就是空間不足。當(dāng)然,你可能本身就知道,用 df 命 令,就能查看文件系統(tǒng)的磁盤空間使用情況。比如:

          df /dev/vda1
          文件系統(tǒng)           1K-塊         已用         可用        已用%    掛載點
          /dev/vda1      104846316     28228044     76618272      27%     /

          可以看到,我的根文件系統(tǒng)只使用了 27% 的空間。這里還要注意,總空間用 1K- blocks 的數(shù)量來表示,你可以給 df 加上 -h 選項,以獲得更好的可讀性:

          df -h /dev/vda1
           文件系統(tǒng)         容量     已用     可用   已用%   掛載點
          /dev/vda1       100G     27G      74G   27%     /

          不過有時候,明明碰到了空間不足的問題,可是用 df 查看磁盤空間后,卻發(fā)現(xiàn)剩余空間還有很多。這是怎么回事呢?

          其實除了文件數(shù)據(jù),索引節(jié)點也占用磁盤空間。可以給 df 命令加上 -i 參數(shù),查看索引節(jié)點的使用情況,如下所示:

          df -h -i /dev/vda1
          文件系統(tǒng)         Inode    已用(I)   可用(I)   已用(I)%  掛載點
          /dev/vda1        50M     162K     50M        1%       /

          索引節(jié)點的容量,(也就是 Inode 個數(shù))是在格式化磁盤時設(shè)定好的,一般由格式化工具自動生成。當(dāng)發(fā)現(xiàn)索引節(jié)點空間不足,但磁盤空間充足時,很可能就是過多小文件導(dǎo)致的。

          所以,一般來說,刪除這些小文件,或者把它們移動到索引節(jié)點充足的其他磁盤中,就可以解決這個問題。

          緩存

          可以用 free 或 vmstat,來觀察頁緩存的大小。free 輸出的 Cache,是頁緩存和可回收 Slab 緩存的和,你可以從 /proc/meminfo ,直接得到它們的大?。?/p>

          cat /proc/meminfo | grep -E "SReclaimable|Cached"
          Cached:          2014100 kB
          SwapCached:         5316 kB
          SReclaimable:     216128 kB

          話說回來,文件系統(tǒng)中的目錄項和索引節(jié)點緩存,又該如何觀察呢?

          實際上,內(nèi)核使用 Slab 機制,管理目錄項和索引節(jié)點的緩存。/proc/meminfo 只給出了 Slab 的整體大小,具體到每一種 Slab 緩存,還要查看 /proc/slabinfo 這個文件。

          比如,運行下面的命令,你就可以得到,所有目錄項和各種文件系統(tǒng)索引節(jié)點的緩存情況:

          # name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunab
          cat /proc/slabinfo | grep -E '^#|dentry|inode'
          # name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
          ovl_inode             66     66    736   22    4 : tunables    0    0    0 : slabdata      3      3      0
          fuse_inode             0      0    832   19    4 : tunables    0    0    0 : slabdata      0      0      0
          xfs_inode         100470 110736   1024   16    4 : tunables    0    0    0 : slabdata   6921   6921      0
          mqueue_inode_cache     64     64   1024   16    4 : tunables    0    0    0 : slabdata      4      4      0
          hugetlbfs_inode_cache     48     48    680   24    4 : tunables    0    0    0 : slabdata      2      2      0
          sock_inode_cache    4581   4807    704   23    4 : tunables    0    0    0 : slabdata    209    209      0
          shmem_inode_cache   1816   2541    760   21    4 : tunables    0    0    0 : slabdata    121    121      0
          proc_inode_cache   10210  13024    728   22    4 : tunables    0    0    0 : slabdata    592    592      0
          inode_cache        36498  38832    656   24    4 : tunables    0    0    0 : slabdata   1618   1618      0
          dentry            150086 183204    192   21    1 : tunables    0    0    0 : slabdata   8724   8724      0

          這個界面中,dentry 行表示目錄項緩存,inode_cache 行,表示 VFS 索引節(jié)點緩存,其 余的則是各種文件系統(tǒng)的索引節(jié)點緩存。

          /proc/slabinfo 的列比較多,具體含義可以查詢 man slabinfo。在實際性能分析中,我們更常使用 slabtop ,來找到占用內(nèi)存最多的緩存類型。

          比如,下面就是運行 slabtop 得到的結(jié)果:

          # 按下 c 按照緩存大小排序,按下 a 按照活躍對象數(shù)排序 
          slabtop
          Active / Total Objects (% used)    : 991123 / 1087653 (91.1%)
           Active / Total Slabs (% used)      : 40627 / 40627 (100.0%)
           Active / Total Caches (% used)     : 103 / 138 (74.6%)
           Active / Total Size (% used)       : 329426.37K / 371563.66K (88.7%)
           Minimum / Average / Maximum Object : 0.01K / 0.34K / 8.00K

           OBJS  ACTIVE   USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE    NAME                   
          183204 150026   81%    0.19K   8724      21       34896K    dentry
           38832  36498   93%    0.64K   1618      24       25888K    inode_cache
          ....
            6174   6009   97%    0.19K   294      21       1176K    cred_jar
            6066   5878   96%    0.44K   337      18       2696K    xfrm_dst_cache
            5950   5950   100%   0.02K   35      170      140K     avtab_node
            4807   4581   95%    0.69K   209      23       3344K    sock_inode_cache
            3948   3812   96%    1.12K   141      28       4512K    signal_cache
            3744   3680   98%    0.25K   234      16       936K     skbuff_head_cache
            3634   3634   100%   0.09K   79      46       316K     trace_event_file

          從這個結(jié)果你可以看到,在我的系統(tǒng)中,目錄項(dentry)和索引節(jié)點(inode_cache)占用了最多的 Slab 緩存。不 過它們占用的內(nèi)存其實并不大,加起來也只有 60MB 左右。

          6總結(jié)

          文件系統(tǒng),是對存儲設(shè)備上的文件,進(jìn)行組織管理的一種機制。為了支持各類不同的文件系統(tǒng),Linux 在各種文件系統(tǒng)實現(xiàn)上,抽象了一層虛擬文件系統(tǒng)(VFS)。

          VFS 定義了一組所有文件系統(tǒng)都支持的數(shù)據(jù)結(jié)構(gòu)和標(biāo)準(zhǔn)接口。這樣,用戶進(jìn)程和內(nèi)核中的其他子系統(tǒng),就只需要跟 VFS 提供的統(tǒng)一接口進(jìn)行交互。

          為了降低慢速磁盤對性能的影響,文件系統(tǒng)又通過頁緩存、目錄項緩存以及索引節(jié)點緩存,緩和磁盤延遲對應(yīng)用程序的影響。

          來自:杰哥的IT之旅

          往期推薦

          開源~新款裝機神器!啟動 U盤 告別格式化,直接掛載多 ISO

          Linux 服務(wù)器日常巡檢腳本分享

          終于有人把Prometheus入門講明白了

          Redis中主、從庫宕機如何恢復(fù)?

          Linux 標(biāo)準(zhǔn)大頁和透明大頁

          文件存儲、對象存儲、塊存儲分不清楚?看完就懂了

          黑客 Shell 神技:掩蓋 Linux 服務(wù)器上的操作痕跡

          徹底搞懂 Nginx 的五大應(yīng)用場景

          一網(wǎng)打盡大廠MongoDB面試題

          存儲系統(tǒng)基礎(chǔ)知識介紹

          深入研究Docker聯(lián)合文件系統(tǒng)

          Linux交換分區(qū)要點匯總

          如何優(yōu)雅的在 Linux 下開機自動重啟腳本

          18個工具分析Linux占用網(wǎng)絡(luò)帶寬大的進(jìn)程

          超全面的 Kubernetes 容器網(wǎng)絡(luò)技能,運維看后都說好

          關(guān)注「開源Linux」加星標(biāo),提升IT技能


          有收獲,點個在看 
          瀏覽 27
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  穿丝袜日逼网站 | 最新做爱网站 | 日本免费黄色电影网站 | 日韩不卡一区 | 影音先锋美女 |