同CPU、記憶體一樣,磁盤和檔案系統的管理也是作業系統最核心的功能
- 磁盤為系統提供了最基本的持久化存盤
- 檔案系統則在磁盤的基礎上提供了一個用來管理檔案的樹狀結構
那么,磁盤和檔案系統是怎么作業的呢?又有哪些指標可以衡量它們的性能呢?
接下來看看Linux檔案系統的作業原理
一、索引節點和目錄項
1.1 檔案系統定義
檔案系統,本身是對存盤設備上的檔案進行組織管理的機制,組織方式不同,就會形成不同的檔案系統
需要記住最重要的一點,在Linux中一切皆檔案,不僅普通的檔案和目錄,就連塊設備、套接字、管道等也都要通過統一的檔案系統來管理
1.2 檔案目錄結構記錄
為了方便管理Linux檔案系統為每個檔案都分配兩個資料結構,索引節點(index node)和目錄項(directory entry),它們主要用來記錄檔案的元資訊和目錄結構
- 索引節點
簡稱為inode,用來記錄檔案的元資料,比如inode編號、檔案大小、訪問權限、修改日期、資料的位置等
索引節點和檔案一一對應,它跟檔案內容一樣,都會被持久化存盤到磁盤中,所以,索引節點同樣占用磁盤空間
- 目錄項
簡稱為dentry,用來記錄檔案的名字、索引節點指標以及與其他目錄項的關聯關系
多個關聯的目錄項,就構成了檔案系統的目錄結構,不過不同于索引節點,目錄項是由內核維護的一個記憶體資料結構,所以通常也被叫做目錄項快取
換句話說,索引節點是每個檔案的唯一標志,而目錄項維護的是檔案系統的樹狀結構
目錄項和索引節點的關系是多對一,可以簡單理解為一個檔案可以有多個別名
舉個例子,通過硬鏈接為檔案創建的別名會對應不同的目錄項,不過這些目錄項本質上還是鏈接同一個檔案,所以它們的索引節點相同
1.3 檔案資料存盤
索引節點和目錄項紀錄了檔案的元資料,以及檔案間的目錄關系,那么檔案資料到底是怎么存盤的呢?是不是直接寫到磁盤中就好了呢?
實際上,磁盤讀寫的最小單位是扇區,然而扇區只有512B大小,如果每次都讀寫這么小的單位效率一定很低
所以,檔案系統又把連續的扇區組成了邏輯塊,然后每次都以邏輯塊為最小單元來管理資料,常見的邏輯塊大小為4KB,也就是由連續的8個扇區組成
1.4 目錄項、索引節點以及檔案資料的關系
為了幫助理解目錄項、索引節點以及檔案資料的關系,下面示意圖可以把知識和細節串聯起來

這里有兩點需要注意:
- 目錄項本身就是一個記憶體快取,而索引節點則是存盤在磁盤中的資料
為了協調慢速磁盤與快速CPU的性能差異,檔案內容會快取到頁快取Cache中,那么這些索引節點自然也會快取到記憶體中,加速檔案的訪問
- 磁盤在執行檔案系統格式化時會被分成三個存盤區域
分成三個存盤區域,超級塊、索引節點區和資料塊區,其中:
-
超級塊
存盤整個檔案系統的狀態 -
索引節點區
用來存盤索引節點 -
資料塊區
則用來存盤檔案資料
二、虛擬檔案系統
2.1 Linux檔案系統要素
Linux檔案系統的四大基本要素:
- 目錄項
- 索引節點
- 邏輯塊
- 超級塊
2.2 虛擬檔案系統VFS
為了支持各種不同的檔案系統,Linux內核在用戶行程和檔案系統的中間又引入了一個抽象層,也就是虛擬檔案系統VFS(Virtual File System)
VFS定義了一組所有檔案系統都支持的資料結構和標準介面,這樣,用戶行程和內核中的其他子系統,只需要跟VFS提供的統一介面進行互動即可,不需要再關心底層各種檔案系統的實作細節
2.3 檔案系統架構圖
根據下面的Linux檔案系統的架構圖,更好地理解系統呼叫、VFS、快取、檔案系統以及塊存盤之間的關系

通過這張圖可以看到在VFS的下方,Linux支持各種各樣的檔案系統,如Ext4、XFS、 NFS等等
2.4 檔案系統類別
按照存盤位置的不同,這些檔案系統可以分為三類:
-
基于磁盤的檔案系統
也就是把資料直接存盤在計算機本地掛載的磁盤中
常見的Ext4、XFS、OverlayFS等都是這類檔案系統 -
基于記憶體的檔案系統
也就是常說的虛擬檔案系統
這類檔案系統不需要任何磁盤分配存盤空間,但會占用記憶體
經常用到的/proc檔案系統其實就是一種最常見的虛擬檔案系統,此外/sys檔案系統也屬于這一類,主要向用戶空間匯出層次化的內核物件 -
網路檔案系統
也就是用來訪問其他計算機資料的檔案系統
比如NFS、SMB、 iSCSI等
這些檔案系統要先掛載到VFS目錄樹中的某個子目錄(稱為掛載點),然后才能訪問其中的檔案
以基于磁盤的檔案系統為例,在安裝系統時要先掛載一個根目錄(/),在根目錄下再把其他檔案系統(比如其他的磁盤磁區、/proc檔案系統、/sys檔案系 統、NFS等)掛載進來
三、檔案系統I/O
把檔案系統掛載到掛載點后,能夠通過掛載點再去訪問它管理的檔案
VFS 提供了一組標準的檔案訪問介面,這些介面以系統呼叫的方式提供給應用程式使用
3.1 cat命令實體
以cat命令為例:
首先呼叫open()打開一個檔案
然后呼叫read()讀取檔案的內容
最后呼叫write()把檔案內容輸出到控制臺的標準輸出中
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);
3.2 檔案讀寫方式分類
檔案讀寫方式的各種差異導致I/O的分類多種多樣
最常見的有:
- 緩沖與非緩沖I/O
- 直接與非直接I/O
- 阻塞與非阻塞I/O
- 同步與異步I/O
接下來詳細看這四種I/O分類
3.3 緩沖與非緩沖I/O
第一種,根據是否利用標準庫快取可以把檔案I/O分為緩沖I/O與非緩沖I/O
- 緩沖I/O
指利用標準庫快取來加速檔案的訪問,而標準庫內部再通過系統調度訪問檔案
- 非緩沖I/O
指直接通過系統呼叫來訪問檔案,不再經過標準庫快取
注: 這里所說的"緩沖"指標準庫內部實作的快取 比方說,可能見到過很多程式遇到換行時才真正輸出,而換行前的內容其實就是被標準庫暫時快取了起來
無論緩沖I/O還是非緩沖I/O,它們最侄訓是要經過系統呼叫來訪問檔案,系統呼叫后還會通過頁快取來減少磁盤的I/O操作
3.4 直接與非直接I/O
第二種,根據是否利用作業系統的頁快取可以把檔案I/O分為直接I/O與非直接I/O
- 直接I/O
指跳過作業系統的頁快取,直接跟檔案系統互動來訪問檔案
- 非直接I/O
正好相反,檔案讀寫時先要經過系統的頁快取,然后再由內核或額外的系統呼叫真正寫入磁盤
想要實作直接I/O,需要在系統呼叫中指定O_DIRECT標志,如果沒有設定過默認的是非直接I/O
注:直接I/O與非直接I/O,本質上還是和檔案系統互動,如果是在資料庫等場景中,會看到跳過檔案系統讀寫磁盤的情況,也就是通常所說的裸I/O
3.5 阻塞與非阻塞I/O
第三種,根據應用程式是否阻塞自身運行可以把檔案I/O分為阻塞I/O和非阻塞I/O
- 阻塞I/O
指應用程式執行I/O操作后,如果沒有獲得回應就會阻塞當前執行緒,自然就不能執行其他任務
- 非阻塞I/O
指應用程式執行I/O操作后不會阻塞當前的執行緒,可以繼續執行其他的任務,隨后再通過輪詢或者事件通知的形式獲取呼叫的結果
比方說,訪問管道或者網路套接字時,設定O_NONBLOCK標志就表示用非阻塞方式訪問,而如果不做任何設定,默認的就是阻塞訪問
3.6 同步與異步I/O
第四種,根據是否等待回應結果可以把檔案I/O分為同步和異步I/O
- 同步I/O
指應用程式執行I/O操作后,要一直等到整個I/O完成后才能獲得I/O回應
- 異步I/O
指應用程式執行I/O操作后,不用等待完成和完成后的回應而是繼續執行就可以,等到這次I/O完成后回應會用事件通知的方式告訴應用程式
舉個例子,在操作檔案時:
如果設定了O_SYNC或者O_DSYNC標志就代表同步I/O
如果設定了O_DSYNC就要等檔案資料寫入磁盤后才能回傳,而O_SYNC則是在O_DSYNC基礎上要求檔案元資料也要寫入磁盤后才能回傳
3.7 一切皆檔案
再比如,在訪問管道或者網路套接字時設定了O_ASYNC選項后,相應的I/O就是異步I/O,這樣,內核會再通過SIGIO或者SIGPOLL來通知行程檔案是否可讀寫
好多概念也經常出現在網路編程中,比如非阻塞I/O,通常會跟select/poll配合用在網路套接字的I/O中
更深刻理解"Linux一切皆檔案"的深刻含義,無論是普通檔案和塊設備、還是網路套接字和管道等,它們都通過統一的VFS介面來訪問
四、性能觀測
學了這么多檔案系統的原理,那如何觀察檔案系統的性能情況呢?
接下來打開一個終端,SSH登錄到服務?上,一起來探索如何觀測檔案系統的性能
4.1 容量
對檔案系統來說,最常見的一個問題就是空間不足
- df命令
用df命令可以查看檔案系統的磁盤空間使用情況,比如:
$ df /dev/sda1
Filesystem 1K?blocks Used Available Use% Mounted on
/dev/sda1 30308240 3167020 27124836 11% /
可以看到根檔案系統只使用了11%的空間
這里需要注意,總空間用1K-blocks的數量來表示,可以給df加上-h選項以獲得更好的可讀性:
$ df ?h /dev/sda1
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 29G 3.1G 26G 11% /
不過有時候明明碰到了空間不足的問題,可是用df查看磁盤空間后卻發現剩余空間還有很多,這是怎么回事呢?
除了檔案資料,索引節點也占用磁盤空間
所以可以給df命令加上-i引數查看索引節點的使用情況,如下:
$ df ?i /dev/sda1
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda1 3870720 157460 3713260 5% /
索引節點的容量(也就是Inode個數)是在格式化磁盤時設定好的,一般由格式化工具自動生成
當發現索引節點空間不足但磁盤空間充足時,很可能就是過多小檔案導致的
所以一般來說,洗掉這些小檔案或者把它們移動到索引節點充足的其他磁盤中,就可以解決這個問題
4.2 快取
使用free或vmstat觀察頁快取的大小,free輸出的Cache是頁快取和可回收Slab快取的和,可以從/proc/meminfo直接得到它們的大小:
$ cat /proc/meminfo | grep ?E "SReclaimable|Cached"
Cached: 748316 kB
SwapCached: 0 kB
SReclaimable: 179508 kB
那檔案系統中的目錄項和索引節點快取,又該如何觀察呢?
實際上,內核使用Slab機制管理目錄項和索引節點的快取,/proc/meminfo只給出了Slab的整體大小,具體到每一種Slab快取還要查看/proc/slabinfo這個檔案
獲取所有目錄項和各種檔案系統索引節點的快取情況,運行下面命令:
$ cat /proc/slabinfo | grep ?E '^#|dentry|inode'
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <
xfs_inode 0 0 960 17 4 : tunables 0 0 0 : slabdata 0 0
...
ext4_inode_cache 32104 34590 1088 15 4 : tunables 0 0 0 : slabdata 2306 2306
sock_inode_cache 1190 1242 704 23 4 : tunables 0 0 0 : slabdata 54 54
shmem_inode_cache 1622 2139 712 23 4 : tunables 0 0 0 : slabdata 93 93
proc_inode_cache 3560 4080 680 12 2 : tunables 0 0 0 : slabdata 340 340
inode_cache 25172 25818 608 13 2 : tunables 0 0 0 : slabdata 1986 1986
dentry 76050 121296 192 21 1 : tunables 0 0 0 : slabdata 5776 5776
這個界面中:
-
dentry行
表示目錄項快取 -
inode_cache行
表示VFS索引節點快取 -
其余行
表示其他各種檔案系統的索引節點快取
在實際性能分析中常使用slabtop來找到占用記憶體最多的快取型別:
# 按下c按照快取大小排序,按下a按斬訓躍物件數排序
$ slabtop
Active / Total Objects (% used) : 277970 / 358914 (77.4%)
Active / Total Slabs (% used) : 12414 / 12414 (100.0%)
Active / Total Caches (% used) : 83 / 135 (61.5%)
Active / Total Size (% used) : 57816.88K / 73307.70K (78.9%)
Minimum / Average / Maximum Object : 0.01K / 0.20K / 22.88K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
69804 23094 0% 0.19K 3324 21 13296K dentry
16380 15854 0% 0.59K 1260 13 10080K inode_cache
58260 55397 0% 0.13K 1942 30 7768K kernfs_node_cache
485 413 0% 5.69K 97 5 3104K task_struct
1472 1397 0% 2.00K 92 16 2944K kmalloc?2048
從這個結果可以看到在系統中,目錄項和索引節點占用了最多的Slab快取,不過它們占用的記憶體其實并不大,加起來也只有23MB左右
五、小結
梳理了Linux檔案系統的作業原理
檔案系統,是對存盤設備上的檔案進行組織管理的一種機制
為了支持各類不同的檔案系統,Linux在各種檔案系統實作上抽象了一層虛擬檔案系統(VFS)
VFS 定義了一組所有檔案系統都支持的資料結構和標準介面,這樣,用戶行程和內核中的其他子系統就只需要跟VFS提供的統一介面進行互動
為了降低慢速磁盤對性能的影響,檔案系統又通過頁快取、目錄項快取以及索引節點快取,緩和磁盤延遲對應用程式的影響
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/287714.html
標籤:其他
