想弄清楚Linux文件系統(tǒng)的運(yùn)行機(jī)制嗎?
Linux文件系統(tǒng)作為操作系統(tǒng)的核心組成部分,其運(yùn)行機(jī)制也是我們程序員需要了解和掌握的,磁盤為系統(tǒng)提供了最基本的持久化存儲(chǔ),文件系統(tǒng)則在磁盤的基礎(chǔ)上提供系統(tǒng)里所有文件的管理,在Linux里一切皆文件,不僅普通的文件和目錄,就連塊設(shè)備、套接字、管道等,也都要通過統(tǒng)一的文件系統(tǒng)來管理。今天我們就一起來聊一聊:磁盤和文件系統(tǒng)是怎么工作的?
索引節(jié)點(diǎn)和目錄項(xiàng)
在Linux文件系統(tǒng)中,一個(gè)文件的元數(shù)據(jù)包括:目錄項(xiàng)、索引節(jié)點(diǎn)、數(shù)據(jù)塊。
- 目錄項(xiàng):簡稱為dentry,用來記錄文件的名字、索引節(jié)點(diǎn)指針以及與其他目錄項(xiàng)的關(guān)聯(lián)關(guān)系。多個(gè)關(guān)聯(lián)的目錄項(xiàng),就構(gòu)成了文件系統(tǒng)的目錄結(jié)構(gòu)。目錄項(xiàng)是由內(nèi)核維護(hù)的一個(gè)內(nèi)存數(shù)據(jù)結(jié)構(gòu),所以通常也被叫做目錄項(xiàng)緩存(Cache)。
- 索引節(jié)點(diǎn):簡稱為inode,用來記錄文件的元數(shù)據(jù),包括inode 編號(hào)、文件大小、訪問權(quán)限、修改日期、數(shù)據(jù)的位置、鏈接數(shù)等,索引節(jié)點(diǎn)信息會(huì)持久化到磁盤中存儲(chǔ),占用磁盤空間。
- 數(shù)據(jù)塊: 簡稱為block,存儲(chǔ)文件數(shù)據(jù)的地方。磁盤的最小存儲(chǔ)單位叫做扇區(qū)(Sector),每個(gè)扇區(qū)存儲(chǔ)512字節(jié),相當(dāng)于0.5KB,操作系統(tǒng)讀取硬盤的時(shí)候,不會(huì)一個(gè)扇區(qū)一個(gè)扇區(qū)地讀取,這樣效率太低,而是一次性連續(xù)讀取多個(gè)扇區(qū),即一次性讀取一個(gè)"塊"(block)。這種由多個(gè)扇區(qū)組成的"塊",是文件存取的最小單位。"塊"的大小,最常見的是4KB(八個(gè)sector)。
索引節(jié)點(diǎn)是存儲(chǔ)在硬盤上的數(shù)據(jù),那么為了加速文件的訪問,通常會(huì)把索引節(jié)點(diǎn)加載到內(nèi)存中。另外,磁盤進(jìn)行格式化的時(shí)候,會(huì)被分成三個(gè)存儲(chǔ)區(qū)域,分別是超級(jí)塊、索引節(jié)點(diǎn)區(qū)和數(shù)據(jù)塊區(qū)。
- 超級(jí)塊,用來存儲(chǔ)文件系統(tǒng)的詳細(xì)信息,比如塊個(gè)數(shù)、塊大小、空閑塊等等。
- 索引節(jié)點(diǎn)區(qū),用來存儲(chǔ)索引節(jié)點(diǎn)。
- 數(shù)據(jù)塊區(qū),用來存儲(chǔ)文件或目錄數(shù)據(jù)。
虛擬文件系統(tǒng)
Linux系統(tǒng)中的虛擬文件系統(tǒng)(VFS,Virtual File System)是一個(gè)抽象層,用于提供統(tǒng)一的文件系統(tǒng)接口,使得用戶和應(yīng)用程序能夠以相同的方式訪問不同類型的文件系統(tǒng),而無需關(guān)心底層文件系統(tǒng)的具體實(shí)現(xiàn)。
用戶程序和 glibc 庫都是屬于用戶空間的,本質(zhì)都是用戶程序。應(yīng)用層的程序和glibc通過調(diào)用“系統(tǒng)調(diào)用層(SCI)”的函數(shù),完成對(duì)文件的操作。這些函數(shù)是 Linux 內(nèi)核對(duì)外提供的函數(shù)接口,用戶通過這些函數(shù)向系統(tǒng)申請操作。比如系統(tǒng)cat命令,它首先調(diào)用open()函數(shù) ,打開一個(gè)文件;然后調(diào)用read() 函數(shù),讀取文件的內(nèi)容;最后再調(diào)用 write()函數(shù) ,把文件內(nèi)容輸出到控制臺(tái)的標(biāo)準(zhǔn)輸出中。常見的文件系統(tǒng)類型又可以分為以下幾大類:
- 基于本地磁盤:EXT3、EXT4、XFS、OverlayFS 等。這類文件系統(tǒng)的特點(diǎn)是數(shù)據(jù)直接存儲(chǔ)在計(jì)算機(jī)本地掛載的磁盤中,性能好,沒有網(wǎng)絡(luò)IO的訪問消耗。
- 基于網(wǎng)絡(luò)文件系統(tǒng):NFS、CIFS/SMB、CephFS、GlusterFS等,這類文件的特點(diǎn)是它們允許用戶通過網(wǎng)絡(luò)訪問和管理文件。分布式、跨平臺(tái)、靈活性和可擴(kuò)縮性是它們的最大優(yōu)勢。
- 基于內(nèi)存文件系統(tǒng):tmpfs、ramfs、/proc等,這些基于內(nèi)存的文件系統(tǒng)通常用于特定的用途,如臨時(shí)文件存儲(chǔ)、緩存、快速數(shù)據(jù)訪問等。它們提供了在內(nèi)存中進(jìn)行文件讀寫操作的高性能解決方案,但也需要注意內(nèi)存限制和數(shù)據(jù)易失性的特點(diǎn)。
文件 I/O
我們對(duì)磁盤進(jìn)行的分區(qū)、格式化這些操作就是建立不同類型的文件系統(tǒng),這些文件系統(tǒng)需要通過mount的方式掛載到Linux的VFS上的某個(gè)目錄才能被系統(tǒng)使用,應(yīng)用程序?qū)ξ募淖x寫有不同的方式,也就是我們常說的I/O類型,以下是我們常見的I/O類型。
緩沖與非緩沖I/O
- 所謂不帶緩沖,并不是指內(nèi)核不提供緩沖,而是只單純的系統(tǒng)調(diào)用,不是函數(shù)庫的調(diào)用。系統(tǒng)內(nèi)核對(duì)磁盤的讀寫都會(huì)提供一個(gè)塊緩沖,當(dāng)用write函數(shù)對(duì)其寫數(shù)據(jù)時(shí),直接調(diào)用系統(tǒng)調(diào)用,將數(shù)據(jù)寫入到塊緩沖進(jìn)行排隊(duì),當(dāng)塊緩沖達(dá)到一定的量時(shí),才會(huì)把數(shù)據(jù)寫入磁盤。因此所謂的不帶緩沖的I/O是指進(jìn)程不提供緩沖功能。每調(diào)用一次write或read函數(shù),直接系統(tǒng)調(diào)用。(內(nèi)核提供緩沖的)。
- 而帶緩沖的I/O是指進(jìn)程對(duì)輸入輸出流進(jìn)行了改進(jìn),提供了一個(gè)流緩沖。當(dāng)用write函數(shù)寫數(shù)據(jù)時(shí),先把數(shù)據(jù)寫入流緩沖區(qū)中,當(dāng)達(dá)到一定條件,比如流緩沖區(qū)滿了,這時(shí)候才會(huì)把數(shù)據(jù)一次送往內(nèi)核提供的塊緩沖,再經(jīng)塊緩沖寫入磁盤。(雙重緩沖)
- 因此,帶緩沖的I/O在往磁盤寫入相同的數(shù)據(jù)量時(shí),會(huì)比不帶緩沖的I/O調(diào)用系統(tǒng)調(diào)用的次數(shù)要少。
直接 I/O與非直接I/O
- 直接I/O:就是應(yīng)用程序直接訪問磁盤數(shù)據(jù),而不經(jīng)過內(nèi)核緩沖區(qū),這樣做的目的是減少一次從內(nèi)核緩沖區(qū)到用戶程序緩存的數(shù)據(jù)復(fù)制。
- 非直接I/O:就是文件讀寫時(shí),先要經(jīng)過系統(tǒng)的頁緩存,然后再由內(nèi)核或額外的系統(tǒng)調(diào)用后寫入磁盤。
- 對(duì)于直接I/O,如果訪問的數(shù)據(jù)不在應(yīng)用程序緩存中,那么每次數(shù)據(jù)都會(huì)直接從磁盤加載,這種直接加載的效率會(huì)比較慢。但是類型于數(shù)據(jù)庫管理系統(tǒng)這類應(yīng)用,它們更傾向于選擇它們自己的緩存機(jī)制,因?yàn)閿?shù)據(jù)庫管理系統(tǒng)往往比操作系統(tǒng)更了解數(shù)據(jù)庫中存放的數(shù)據(jù),使用直接I/O更合適。
阻塞I/O和非阻塞I/O
- 阻塞I/O:應(yīng)用進(jìn)程調(diào)用I/O操作時(shí)阻塞,只有等待要操作的數(shù)據(jù)準(zhǔn)備好,并復(fù)制到應(yīng)用進(jìn)程的緩沖區(qū)中才返回。特點(diǎn)是:實(shí)現(xiàn)難度低、開發(fā)應(yīng)用較容易,適用并發(fā)量小的網(wǎng)絡(luò)應(yīng)用開發(fā)。
- 非阻塞I/O:是指應(yīng)用程序執(zhí)行 I/O 操作后,不會(huì)阻塞當(dāng)前的線程,可以繼續(xù)執(zhí)行其他的任務(wù),隨后再通過輪詢或者事件通知的形式,獲取調(diào)用的結(jié)果。特點(diǎn)是:相對(duì)來說復(fù)雜一些。適用并發(fā)量較小、且不需要及時(shí)響應(yīng)的網(wǎng)絡(luò)應(yīng)用開發(fā)
同步和異步 I/O
- 同步I/O:是指應(yīng)用程序執(zhí)行 I/O 操作后,要一直等到整個(gè) I/O 完成后,才能獲得 I/O 響應(yīng)。
- 異步I/O:是指應(yīng)用程序執(zhí)行 I/O 操作后,不用等待完成和完成后的響應(yīng),而是繼續(xù)執(zhí)行就可以。等到這次 I/O 完成后,響應(yīng)會(huì)用事件通知的方式,告訴應(yīng)用程序。
關(guān)于文件的一些常見小知識(shí)
磁盤剩余空間還很多,新建文件和目錄報(bào)空間不足。
- 排查思路:大概率是小文件太多,inode用完了,可以使用df -i。
du和df統(tǒng)計(jì)的硬盤使用情況不一致問題。
- du是統(tǒng)計(jì)被文件系統(tǒng)記錄到的每個(gè)文件的大小,然后進(jìn)行累加得到的總大小,是通過文件系統(tǒng)獲取到的。而df主要是從超級(jí)塊(superblock)中讀入硬盤使用信息,df獲取到的是磁盤塊被使用的情況。產(chǎn)生這種情況大概率是有文件被刪除了,但是有別的進(jìn)程正在使用它(占有句柄),可以通過lsof | grep deleted查到。當(dāng)進(jìn)程停止或者被kill時(shí),這些空間將被釋放。
我們查詢磁盤容量的時(shí)候,Used+Avail的大小為啥總是小于總?cè)萘浚⊿Ize)。
- 為了預(yù)防緊急情況,linux ext文件系統(tǒng)會(huì)預(yù)留部分硬盤空間,具體預(yù)留的數(shù)值可以通過tune2fs -l [dev_name] | grep “Reserved block count”查看到,(dev_name)是設(shè)備名,這里預(yù)留的空間會(huì)被df計(jì)算到已用空間中,從而導(dǎo)致df和du統(tǒng)計(jì)不一致。如果需要調(diào)整預(yù)留空間大小, 我們可以使用tune2fs -m [size] [dev_name]來進(jìn)行調(diào)整。