儲存系統科普——檔案系統介紹
簡介
該篇blog只是儲存系列科普文章中的第二篇,所有文章請參考:
在工程架構領域裡,儲存是一個非常重要的方向,這個方向從底至上,我分成了如下幾個層次來介紹:
- 硬體層:講解磁碟,SSD,SAS, NAS, RAID等硬體層的基本原理,以及其為作業系統提供的儲存介面;
- 作業系統層:即檔案系統,作業系統如何將各個硬體管理並對上提供更高層次介面;
- 單機引擎層:常見儲存系統對應單機引擎原理大概介紹,利用檔案系統介面提供更高級別的儲存系統介面;
- 分散式層:如何將多個單機引擎組合成一個分散式儲存系統;
- 查詢層:使用者典型的查詢語義表達以及解析;
檔案系統磁碟分配
在儲存知識棧上提到檔案系統, 大家首先就關心他是如何管理好硬體層提供的磁碟空間的。
本文開篇就先描述典型的幾種檔案系統管理磁碟的技術方案: 連續分配, 鏈式分配, 索引分配。
連續分配
顧名思義, 就是建立檔案的時候, 給分配一組連續的塊。在單獨拿出一塊地方儲存各個檔案的meta資訊, meta資訊也很簡單, 包含檔名, 起始位置和長度即可, 這個存放meta資訊的地方也叫做FAT(文件分配表)。
如下圖:
該方案的優點:
- 簡便, 適用於一次性寫入操作;
- 所需磁碟尋道次數和尋道時間最少;
缺點也很明顯:
- 檔案不能動態增長, 因為後面的塊可能已經分配給別人了;
- 不利於檔案的插入和刪除, 插入檔案之前需要宣告檔案大小;
- 外部碎片問題;
為了克服連續分配的問題, 又進化出來了鏈式分配方案。
鏈式分配
鏈式分配即將檔案塊像連結串列一樣管理起來, 每個塊中放一個指標, 指標指向下一個檔案塊所在的位置。這樣在FAT中儲存也很簡單, 只需要儲存檔名, 起始塊號和結束塊號(都可以不存)。
如下圖:
該方案的優點:
- 提高磁碟利用率, 沒有碎片問題
- 有利於檔案的插入, 刪除
缺點:
- 存取速度慢, 需要移動的磁軌次數多, 尋道時間長;
- 讀寫任何一個地方都需要沿著指標前進直到找到對應塊為止;
- 連結佔據了一定的磁碟空間, 資料不是嚴格按照塊大小分配;
索引分配
這是一個折衷方案, 也是現在大部分檔案系統採用的方案, 他綜合了連續分配和鏈式分配的好處。
該方案會在FAT中儲存所有檔案塊的位置, 各檔案系統都有一套自己對應的細節分配策略, 會保證一個檔案儘量連續的同時, 又避免出現大量的磁碟碎片。
如下圖:
該方案的優點是:
- 能夠保持好大部分檔案的區域性性
- 滿足檔案插入, 刪除的高效
- 隨機讀寫不需要沿著指標前進
缺點:
- 會有較多的磁碟尋道次數
- 索引表本身管理複雜, 也會帶來額外的系統開銷
ext檔案系統
基本概念
- 塊. 即Block, 資料儲存的最小單元, 每個塊都有一個唯一的地址, 從0開始, 起源於第一個可以用來儲存資料的扇區;
- 超級塊. 超級塊儲存了各種檔案系統的meta資訊, 比如塊大小資訊。他位於檔案系統的2號和3號扇區(實體地址), 佔用兩個扇區大小;
- 塊組. 所有的塊會劃分成多個塊組, 每個塊組包含同樣多個塊, 但是可能整個檔案系統整個塊數不是塊組的整數倍, 所以最後一個塊組包含的個數可能會小於其他塊;
總體結構
一個ext檔案系統分成多個塊組, 每個塊組的結構基本相同, 如下:
解釋如下:
- 0~1號扇區: 引導扇區. 如果沒有引導程式碼, 則這兩個扇區為空, 全部用0填充;
-
2~3號扇區: 超級塊, 超級塊包含各種meta資訊:
- 塊大小, 每個塊組包含塊數, 總塊數, 第一個塊前保留塊數, inode節點數, 每個塊組的inode節點數
- 卷名, 最後掛載時間, 掛載路徑, 檔案系統是否乾淨, 是否要呼叫一致性檢查標識
- 空間inode節點和空閒塊的記錄資訊, 在分配inode節點和新塊的時候使用
-
組描述符表:
位於超級塊後面的一個塊, 注意在超級塊之前只佔用了4個扇區, 如果一個塊大小超過4個扇區的話, 這裡就會有空的扇區。
組描述符表中包含了所有塊組的描述資訊, 每個塊組佔據32個位元組(差不多是8個整數的大小)。如果格式化使用預設引數, 那麼組描述符表不會超過一塊塊組。
組描述符和超級塊在每個塊組中都有一個備份, 但是激活了
稀疏超級塊
特徵的情況除外。稀疏超級塊
即不是在所有塊組中都儲存超級塊和組描述符的備份, 預設該策略被啟用, 其策略類似當塊組號是3,5,7的冪的塊組才存副本。 -
塊位圖表
每個塊對應一個bit, 只包含了本塊組的資訊。而檔案系統建立的時候, 預設每個塊組包含的塊數跟每個塊包含的bit數是一樣的, 這種情況下每個塊位圖表正好等於一個塊的大小。
而該位圖表的塊的起始位置會在組描述符表中指定, 大小則為塊組中包含塊數個bit。
-
inode點陣圖塊
跟塊位圖表類似, 通常情況他也只佔用一個塊。通常一個塊組中的inode節點數會小於block數量, 所以其不會超過一個塊大小。
-
inode節點表
每個inode都佔用128位的一個描述資訊, 起始位置在組描述符中表示, 大小為inode節點數*128。
-
資料區
這就是真正儲存資料的區域。
塊大小為4096的時候, 各部分和扇區對應關係如下圖:
塊大小為2048的時候, 各部分和扇區對應關係如下圖:
超級塊詳細資訊
超級塊總是位於檔案系統的第1024~2048位元組處。
超級塊中包含的資訊如下:
偏移(16進位制) | 位元組數 | 含義&解釋 |
---|---|---|
00~03 | 4 | 檔案系統中總inode節點數 |
04~07 | 4 | 檔案系統中總塊數 |
08~0B | 4 | 為檔案系統預保留的塊數 |
0C~0F | 4 | 空閒塊數 |
10~13 | 4 | 空間inode節點數 |
14~17 | 4 | 0號塊組起始塊號 |
18~1B | 4 | 塊大小(1024左移位數) |
1C~1F | 4 | 片段大小, 跟塊大小一模一樣 |
20~23 | 4 | 每個塊組中包含的塊數量 |
24~27 | 4 | 每個塊組中包含的片段數量, 跟包含的快數量一致 |
28~2B | 4 | 每個塊組中包含的inode節點數量 |
2C~2F | 4 | 檔案系統最後掛載時間 |
30~33 | 4 | 檔案系統最後寫入時間 |
34~35 | 2 | 當前掛載數 |
36~37 | 2 | 最大掛載數 |
38~39 | 2 | 檔案系統簽名標識 53EF |
3A~3B | 2 | 檔案系統狀態, 正常, 錯誤, 恢復了孤立的inode節點 |
3C~3D | 2 | 錯誤處理方式, 繼續, 以只讀方式掛載 |
3E~3F | 2 | 輔版本號 |
40~43 | 4 | 最後進行一致性檢查的時間 |
44~47 | 4 | 一致性檢查的間隔時間 |
48~4B | 4 | 建立本檔案系統的作業系統 |
4C~4F | 4 | 主版本號, 只有該值為1的時候, 偏移54之後的擴充套件超級塊的一些動態屬性值才是有意義的 |
50~51 | 2 | 預設為UID的保留塊 |
52~53 | 2 | 預設為GID的保留塊 |
54~57 | 2 | 第一個非保留的inode節點號, 即使用者可以使用的第一個inode節點號 |
58~59 | 2 | 每個inode節點的大小位元組數 |
5A~5B | 2 | 本超級塊所在的塊組號 |
5C~5F | 4 | 相容標識特徵 |
60~63 | 4 | 非相容標識特徵 |
64~67 | 4 | 只讀相容特徵標識 |
68~77 | 16 | 檔案系統ID號 |
78~87 | 16 | 卷名 |
88~C7 | 64 | 最後的掛載路徑 |
C8~CB | 4 | 點陣圖使用的運演算法則 |
CC~CC | 1 | 檔案再分配的塊數 |
CD~CD | 1 | 目錄再分配的塊數 |
CE~CF | 2 | 未使用 |
D0~DF | 16 | 日誌ID |
E0~E3 | 4 | 日誌inode節點 |
E4~E7 | 4 | 日誌裝置 |
E8~EB | 4 | 孤立的inode節點表 |
EC~3FF | 788 | 未使用 |
塊組描述符詳細資訊
每個塊組描述符佔用32個位元組, 其資料結構如下:
偏移(16進位制) | 位元組數 | 含義&解釋 |
---|---|---|
00~03 | 4 | 塊點陣圖起始地址(塊號) |
04~07 | 4 | inode節點點陣圖起始地址(塊號) |
08~0B | 4 | inode節點表起始地址(塊號) |
0C~0D | 2 | 塊組中空閒塊數 |
0E~0F | 2 | 塊組中空閒inode節點數 |
10~11 | 2 | 塊組中的目錄數 |
12~1F | - | 未使用 |
inode資訊
每個inode會被分配給一個目錄或者一個檔案, 每個inode包含了128個位元組, 裡面包含了這個檔案的各種meta資訊。
在所有inode中, 1~10號會用作保留給核心使用, 在這些保留節點中, 2號節點用於儲存根目錄資訊, 1號表示壞塊, 8號表示日誌檔案資訊。
第一個使用者可見的都是從11號inode開始, 11號節點一般用作lost+found
目錄, 當檢查程式發現一個inode節點已經被分配, 但是沒有檔名指向他的時候, 就會把他新增到lost+found
目錄中並賦予一個新的檔名。
inode通過三級指標的方式來找到檔案資料最終儲存的資料塊, 見下圖:
這種方式能保證小檔案的讀取效率的同時, 也支援大檔案的讀取。
目錄項
在ext檔案系統中, 每個目錄也對應一個inode節點, 該inode節點對應的資料塊裡面會儲存該目錄下所有檔案/目錄的資訊。
每個檔案/目錄對應的資訊就叫目錄項
, 目錄項包含的內容也很簡單, 主要就是檔名和指向該檔名的inode指標, 詳細資訊如下:
偏移(16進位制) | 位元組數 | 含義&解釋 |
---|---|---|
00~03 | 4 | inode節點號 |
04~05 | 2 | 本目錄項的長度位元組數 |
06~06 | 1 | 名字長度位元組數 |
07~07 | 1 | 檔案型別 |
08~ | 不定長度 | 名字的ascii碼 |
當檔案刪除的時候, 不會真正刪除檔案, 會將該檔案所屬目錄對應的目錄項給刪除, 同時將對應資料塊在快位圖表中標記為0。
連結
- 硬連結是指在另外一個目錄對應的目錄項中增加一個目錄項。硬連結建立之後, 使用者無法通過檔名來判斷到底哪個是原檔名, 哪個是連結名;
- 軟連線是一種檔案型別, 該檔案裡面就儲存原始檔的完整路徑, 如果原始檔完整路徑長度小於60個位元組, 那麼就將該值直接儲存在inode節點表中, 避免浪費資料塊;
分配策略
- 首先判斷應該在哪個塊組中分配
- 如果是為檔案建立節點
- 預設會在其父目錄所在的組中為其建立節點, 這樣可以確保一個目錄中所有檔案都位於一個大致的區域中
- 如果父目錄所在組沒有空閒的節點或者空閒的塊了, 就到別的塊組中為該檔案分配節點, 找尋別的塊組的演算法如下
- 每次講當前組號加上2^N次方再求hash
- 如果上面的演算法沒找到, 就線性查詢
- 如果是為目錄建立節點
- 會將其分配到可用空間較多的塊組中, 分配演算法如下:
- 首先利用超級塊中的剩餘inode和剩餘塊數字算出每個塊組的平均剩餘數字, 然後依次找到一個大於平均值的塊組
- 如果沒找到, 就利用塊組描述符表中的資訊, 找到一個最空閒的塊組
- 會將其分配到可用空間較多的塊組中, 分配演算法如下:
- 如果是為檔案建立節點
- 當一個數據塊分配給某檔案之後
- 該塊原來的內容會被請出, inode節點對應的各種元資訊會跟著做修改
- 如果是檔案, 節點對應連結數會設定為1, 如果是目錄, 連結數會被設定為2
實際建立/刪除檔案過程
我們建立一個/xuanku/file.txt
, 該檔案大小為10000位元組, 檔案塊大小為4096, 那麼下面來看一下過程:
- 讀取檔案系統的1024位元組~2048位元組, 即超級塊資訊。通過超級塊得到快大小為4096, 每個塊組含有8192個塊以及2008個inode節點
- 讀取檔案系統中第1個塊(即組描述符表), 得到所有塊組佈局資訊
- 訪問2號inode節點(即根節點), 通過讀取根節點資料塊資訊, 假設讀到其位於5號塊
- 在第5號塊所有目錄項中從前往後遍歷, 直到找到檔名為
xuanku
的目錄項, 讀到該inode節點為4724 - 每個塊組有2008個inode, 用4724針對2008取模, 得到的結果是2號塊組
- 通過組描述符表中得到第2個塊組的inode節點表起始於16378號塊
- 從16378號塊讀取inode節點表中查詢4724號對應的inode節點(708號表項), 查詢到該
xuanku
的目錄內容位於17216號塊 - 從17216塊讀取
xuanku
目錄項內容, 將file.txt
相關資訊更新到該塊的目錄項當中 - 然後開始為檔案分配inode節點, 預設會放到父目錄所在塊組, 即2號塊組, 再次2號塊組的inode節點表16378, 開始從4724往後找到第一個可用的inode節點分配給該檔案, 假設找到的是4850號inode。
- 然後就給4850號的inode位圖表設定為1, 組描述符的空閒inode節點數和超級塊的總空閒inode節點數都減1, 將inode節點的地址寫入
file.txt
對應的目錄項當中, 然後寫各種時間, 記錄日誌 - file.txt需要3個塊的儲存空間, 通過2號塊組描述符找到塊點陣圖對應的塊, 並從前往後找到可用的塊。然後將對應的位設定為1, 並更新到inode節點當中
- 然後將檔案的內容寫入到對應的塊中
下面再演示一下將該檔案刪除的過程:
- 讀取檔案系統的1024位元組~2048位元組, 即超級塊資訊。通過超級塊得到快大小為4096, 每個塊組含有8192個塊以及2008個inode節點
- 讀取檔案系統中第1個塊(即組描述符表), 得到所有塊組佈局資訊
- 訪問2號inode節點(即根節點), 通過讀取根節點資料塊資訊, 假設讀到其位於5號塊
- 在第5號塊所有目錄項中從前往後遍歷, 直到找到檔名為
xuanku
的目錄項, 讀到該inode節點為4724 - 每個塊組有2008個inode, 用4724針對2008取模, 得到的結果是2號塊組
- 通過組描述符表中得到第2個塊組的inode節點表起始於16378號塊
- 從16378號塊讀取inode節點表中查詢4724號對應的inode節點(708號表項), 查詢到該
xuanku
的目錄內容位於17216號塊 - 從17216塊讀取
xuanku
目錄項內容, 讀到file.txt
的inode節點為4850 - 然後取消
file.txt
的目錄項分配, 修改系列xuanku
目錄對應的目錄項資訊 - 取消inode節點資訊, 修改2號塊組對應的inode節點表資訊, 將inode節點位設定為0, 更新塊組描述符和超級塊的空閒inode節點數加1
- 還要回收檔案內容對應的6個塊空間, 將塊位圖表中的bit設定為0, 清除inode節點的塊指標, 更新塊組描述符和超級塊的空閒塊數加1
參考
- 資料重新 檔案系統原理精解與資料恢復最佳實踐
- 磁碟分配方式. http://blog.csdn.net/liuqiyao_01/article/details/39156651
- ext線上調整大小. http://www.ibm.com/developerworks/cn/linux/l-cn-ext4resize/