1. 程式人生 > 其它 >Linux效能優化-認識檔案系統

Linux效能優化-認識檔案系統

同cpu、記憶體一樣,磁碟和檔案系統的管理,也是作業系統最核心的功能

磁碟為系統提供了最基本的持久化儲存

檔案系統則在磁碟的基礎上,提供了一個用來管理檔案的樹狀結構

索引節點和目錄項

檔案系統,本身是對儲存裝置上的檔案,進行組織管理的機制。組織方式不同,就會形成不同的檔案系統。

最重要的一點,在 Linux 中一切皆檔案。不僅普通的檔案和目錄,就連塊裝置、套接字、管道等,也都要通過統一的檔案系統來管理。

為了方便管理,Linux 檔案系統為每個檔案都分配兩個資料結構,索引節點(index node)和目錄項(directory entry)。它們主要用來記錄檔案的元資訊和目錄結構。

  • 索引節點
    ,簡稱為 inode,用來記錄檔案的元資料,比如 inode 編號、檔案大小、訪問許可權、修改日期、資料的位置等。索引節點和檔案一一對應,它跟檔案內容一樣,都會被持久化儲存到磁碟中。所以記住,索引節點同樣佔用磁碟空間。
  • 目錄項,簡稱為 dentry,用來記錄檔案的名字、索引節點指標以及與其他目錄項的關聯關係。多個關聯的目錄項,就構成了檔案系統的目錄結構。不過,不同於索引節點,目錄項是由核心維護的一個記憶體資料結構,所以通常也被叫做目錄項快取。

換句話說,索引節點是每個檔案的唯一標誌,而目錄項維護的正是檔案系統的樹狀結構。目錄項和索引節點的關係是多對一,你可以簡單理解為,一個檔案可以有多個別名。

舉個例子,通過硬連結為檔案建立的別名,就會對應不同的目錄項,不過這些目錄項本質上還是連結同一個檔案,所以,它們的索引節點相同。

索引節點和目錄項紀錄了檔案的元資料,以及檔案間的目錄關係,那麼具體來說,檔案資料到底是怎麼儲存的呢?是不是直接寫到磁碟中就好了呢?

實際上,磁碟讀寫的最小單位是扇區,然而扇區只有 512B 大小,如果每次都讀寫這麼小的單位,效率一定很低。所以,檔案系統又把連續的扇區組成了邏輯塊,然後每次都以邏輯塊為最小單元,來管理資料。常見的邏輯塊大小為 4KB,也就是由連續的 8 個扇區組成。

目錄項、索引節點以及檔案資料的關係:

有兩點需要注意

第一,目錄項本身就是一個記憶體快取,而索引節點則是儲存在磁碟中的資料。為了協調慢速磁碟與快速 CPU 的效能差異,檔案內容會快取到頁快取 Cache 中。這些索引節點自然也會快取到記憶體中,加速檔案的訪問。

第二,磁碟在執行檔案系統格式化時,會被分成三個儲存區域,超級塊、索引節點區和資料塊區。

超級塊,儲存整個檔案系統的狀態。

索引節點區,用來儲存索引節點。

資料塊區,則用來儲存檔案資料。虛擬檔案系統

檔案系統I/O

把檔案系統掛載到掛載點後,你就能通過掛載點,再去訪問它管理的檔案了。VFS 提供了一組標準的檔案訪問介面。這些介面以系統呼叫的方式,提供給應用程式使用。

檔案讀寫方式的各種差異,導致 I/O 的分類多種多樣。最常見的有,緩衝與非緩衝 I/O、直接與非直接 I/O、阻塞與非阻塞 I/O、同步與非同步 I/O 等。

第一種,根據是否利用標準庫快取,可以把檔案 I/O 分為緩衝 I/O 與非緩衝 I/O。

  • 緩衝 I/O,是指利用標準庫快取來加速檔案的訪問,而標準庫內部再通過系統排程訪問檔案。
  • 非緩衝 I/O,是指直接通過系統呼叫來訪問檔案,不再經過標準庫快取。

第二,根據是否利用作業系統的頁快取,可以把檔案 I/O 分為直接 I/O 與非直接 I/O。

  • 直接 I/O,是指跳過作業系統的頁快取,直接跟檔案系統互動來訪問檔案。
  • 非直接 I/O 正好相反,檔案讀寫時,先要經過系統的頁快取,然後再由核心或額外的系統呼叫,真正寫入磁碟。

第三,根據應用程式是否阻塞自身執行,可以把檔案 I/O 分為阻塞 I/O 和非阻塞 I/O:

  • 所謂阻塞 I/O,是指應用程式執行 I/O 操作後,如果沒有獲得響應,就會阻塞當前執行緒,自然就不能執行其他任務。
  • 所謂非阻塞 I/O,是指應用程式執行 I/O 操作後,不會阻塞當前的執行緒,可以繼續執行其他的任務,隨後再通過輪詢或者事件通知的形式,獲取呼叫的結果。

第四,根據是否等待響應結果,可以把檔案 I/O 分為同步和非同步 I/O:

  • 所謂同步 I/O,是指應用程式執行 I/O 操作後,要一直等到整個 I/O 完成後,才能獲得 I/O 響應。
  • 所謂非同步 I/O,是指應用程式執行 I/O 操作後,不用等待完成和完成後的響應,而是繼續執行就可以。等到這次 I/O 完成後,響應會用事件通知的方式,告訴應用程式。

有時候,碰到了空間不足的問題,可是用 df 檢視磁碟空間後,卻發現剩餘空間還有很多。這是怎麼回事呢?

除了檔案資料,索引節點也佔用磁碟空間。你可以給 df 命令加上 -i 引數,檢視索引節點的使用情況,如下所示:

$ df -i /dev/sda1

Filesystem Inodes IUsed IFree IUse% Mounted on

/dev/sda1 3870720 157460 3713260 5% /

索引節點的容量,(也就是 Inode 個數)是在格式化磁碟時設定好的,一般由格式化工具自動生成。當你發現索引節點空間不足,但磁碟空間充足時,很可能就是過多小檔案導致的。所以,一般來說,刪除這些小檔案,或者把它們移動到索引節點充足的其他磁碟中,就可以解決這個問題。

快取

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> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
xfs_inode 0 0 960 17 4 : tunables 0 0 0 : slabdata 0 0 0
...
ext4_inode_cache 32104 34590 1088 15 4 : tunables 0 0 0 : slabdata 2306 2306 0hugetlbfs_inode_cache 13 13 624 13 2 : tunables 0 0 0 : slabdata 1 1 0
sock_inode_cache 1190 1242 704 23 4 : tunables 0 0 0 : slabdata 54 54 0
shmem_inode_cache 1622 2139 712 23 4 : tunables 0 0 0 : slabdata 93 93 0
proc_inode_cache 3560 4080 680 12 2 : tunables 0 0 0 : slabdata 340 340 0
inode_cache 25172 25818 608 13 2 : tunables 0 0 0 : slabdata 1986 1986 0
dentry 76050 121296 192 21 1 : tunables 0 0 0 : slabdata 5776 5776 0

這個介面中,dentry 行表示目錄項快取,inode_cache 行,表示 VFS 索引節點快取,其餘的則是各種檔案系統的索引節點快取。

更常使用 slabtop ,來找到佔用記憶體最多的快取型別。比如,下面就是我執行 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

思考題

在實際工作中,我們經常會根據檔名字,查詢它所在路徑,比如:$ find / -name file-name,這個命令,會不會導致系統的快取升高呢?如果有影響,又會導致哪種型別的快取升高呢?

這個命令,會不會導致系統的快取升高呢?

--> 會的

如果有影響,又會導致哪種型別的快取升高呢?

--> /xfs_inode/ proc_inode_cache/dentry/inode_cache

實驗步驟:

1. 清空快取:echo 3 > /proc/sys/vm/drop_caches ; sync

2. 執行find : find / -name test

3. 發現更新top4 項是:

OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME

37400 37400 100% 0.94K 2200 17 35200K xfs_inode

36588 36113 98% 0.64K 3049 12 24392K proc_inode_cache

104979 104979 100% 0.19K 4999 21 19996K dentry

18057 18057 100% 0.58K 1389 13 11112K inode_cache

find / -name 這個命令是全盤掃描(既包括記憶體檔案系統又包含本地的xfs【我的環境沒有mount 網路檔案系統】),所以 inode cache & dentry & proc inode cache 會升高。

另外,執行過了一次後再次執行find 就機會沒有變化了,執行速度也快了很多,也就是下次的find大部分是依賴cache的結果。