您的位置: 首頁>>關(guān)于我們>>行業(yè)動態(tài) |
和 CPU、內(nèi)存相同,磁盤和文件體系的辦理,也是操作體系最核心的功能。
磁盤為體系供給了最基本的持久化存儲。
文件體系則在磁盤的基礎(chǔ)上,供給了一個用來辦理文件的樹狀結(jié)構(gòu)。
那么,磁盤和文件體系是怎么作業(yè)的呢?又有哪些目標(biāo)能夠衡量它們的功能呢?
索引節(jié)點和目錄項
文件體系,本身是對存儲設(shè)備上的文件,進(jìn)行安排辦理的機(jī)制。安排方法不同,就會構(gòu)成不同的文件體系。
咱們要記住最重要的一點,在 Linux 中一切皆文件。不只普通的文件和目錄,就連塊設(shè)備、 套接字、管道等,也都要經(jīng)過一致的文件體系來辦理。
為了方便辦理,Linux 文件體系為每個文件都分配兩個數(shù)據(jù)結(jié)構(gòu),索引節(jié)點(index node)和目錄項(directory entry)。它們首要用來記載文件的元信息和目錄結(jié)構(gòu)。
索引節(jié)點,簡稱為 inode,用來記載文件的元數(shù)據(jù),比方 inode 編號、文件巨細(xì)、拜訪 權(quán)限、修正日期、數(shù)據(jù)的位置等。索引節(jié)點和文件一一對應(yīng),它跟文件內(nèi)容相同,都會 被持久化存儲到磁盤中。所以記住,索引節(jié)點同樣占用磁盤空間。
目錄項,簡稱為 dentry,用來記載文件的名字、索引節(jié)點指針以及與其他目錄項的相關(guān) 聯(lián)系。多個相關(guān)的目錄項,就構(gòu)成了文件體系的目錄結(jié)構(gòu)。不過,不同于索引節(jié)點,目錄項是由內(nèi)核保護(hù)的一個內(nèi)存數(shù)據(jù)結(jié)構(gòu),所以一般也被叫做目錄項緩存。
換句話說,索引節(jié)點是每個文件的唯一標(biāo)志,而目錄項保護(hù)的正是文件體系的樹狀結(jié)構(gòu)。目錄項和索引節(jié)點的聯(lián)系是多對一,你能夠簡單了解為,一個文件能夠有多個別號。
舉個比方,經(jīng)過硬鏈接為文件創(chuàng)建的別號,就會對應(yīng)不同的目錄項,不過這些目錄項本質(zhì)上仍是鏈接同一個文件,所以,它們的索引節(jié)點相同。
索引節(jié)點和目錄項紀(jì)錄了文件的元數(shù)據(jù),以及文件間的目錄聯(lián)系,那么具體來說,文件數(shù)據(jù)到底是怎么存儲的呢?是不是直接寫到磁盤中就好了呢?
實際上,磁盤讀寫的最小單位是扇區(qū),然而扇區(qū)只要 512B 巨細(xì),假如每次都讀寫這么小的單位,功率必定很低。所以,文件體系又把接連的扇區(qū)組成了邏輯塊,然后每次都以邏 輯塊為最小單元,來辦理數(shù)據(jù)。常見的邏輯塊巨細(xì)為 4KB,也便是由接連的 8 個扇區(qū)組成。
為了協(xié)助咱們了解目錄項、索引節(jié)點以及文件數(shù)據(jù)的聯(lián)系,畫了一張示意圖。咱們能夠?qū)φ罩@張圖,來回憶剛剛講過的內(nèi)容,把知識和細(xì)節(jié)串聯(lián)起來。
不過,這里有兩點需要咱們注意:
榜首,目錄項本身便是一個內(nèi)存緩存,而索引節(jié)點則是存儲在磁盤中的數(shù)據(jù)。在前面的 Buffer 和 Cache 原理中,我從前提到過,為了協(xié)調(diào)慢速磁盤與快速 CPU 的功能差異,文 件內(nèi)容會緩存到頁緩存 Cache 中。那么,咱們也應(yīng)該想到,這些索引節(jié)點天然也會緩存到內(nèi)存中,加快文件的拜訪。
第二,磁盤在履行文件體系格式化時,會被分紅三個存儲區(qū)域,超級塊、索引節(jié)點區(qū)和數(shù)
據(jù)塊區(qū)。其間,
超級塊,存儲整個文件體系的狀態(tài)。
索引節(jié)點區(qū),用來存儲索引節(jié)點。
數(shù)據(jù)塊區(qū),則用來存儲文件數(shù)據(jù)。
虛擬文件體系
目錄項、索引節(jié)點、邏輯塊以及超級塊,構(gòu)成了 Linux 文件體系的四大基本要素。不過, 為了支撐各種不同的文件體系,Linux 內(nèi)核在用戶進(jìn)程和文件體系的中心,又引入了一個籠統(tǒng)層,也便是虛擬文件體系 VFS(Virtual File System)。
VFS 定義了一組一切文件體系都支撐的數(shù)據(jù)結(jié)構(gòu)和規(guī)范接口。這樣,用戶進(jìn)程和內(nèi)核中的其他子體系,只需要跟 VFS 供給的一致接口進(jìn)行交互就能夠了,而不需要再關(guān)心底層各種文件體系的完結(jié)細(xì)節(jié)。
這里,下圖是 Linux 文件體系的架構(gòu)圖,幫咱們更好地了解體系調(diào)用、VFS、緩存、文 件體系以及塊存儲之間的聯(lián)系。
經(jīng)過這張圖,能夠看到,在 VFS 的下方,Linux 支撐各種各樣的文件體系,如 Ext4、 XFS、NFS 等等。依照存儲位置的不同,這些文件體系能夠分為三類。
榜首類是依據(jù)磁盤的文件體系,也便是把數(shù)據(jù)直接存儲在計算機(jī)本地掛載的磁盤中。常見的 Ext4、XFS、OverlayFS 等,都是這類文件體系。
第二類是依據(jù)內(nèi)存的文件體系,也便是咱們常說的虛擬文件體系。這類文件體系,不需要任何磁盤分配存儲空間,但會占用內(nèi)存。咱們經(jīng)常用到的 /proc 文件體系,其實便是 一種最常見的虛擬文件體系。此外,/sys 文件體系也歸于這一類,首要向用戶空間導(dǎo)出層次化的內(nèi)核目標(biāo)。
第三類是網(wǎng)絡(luò)文件體系,也便是用來拜訪其他計算機(jī)數(shù)據(jù)的文件體系,比方 NFS、 SMB、iSCSI 等。
這些文件體系,要先掛載到 VFS 目錄樹中的某個子目錄(稱為掛載點),然后才干拜訪其間的文件。拿榜首類,也便是依據(jù)磁盤的文件體系為例,在裝置體系時,要先掛載一個根 目錄(/),在根目錄下再把其他文件體系(比方其他的磁盤分區(qū)、/proc 文件體系、/sys 文件體系、NFS 等)掛載進(jìn)來。
文件體系 I/O
把文件體系掛載到掛載點后,你就能經(jīng)過掛載點,再去拜訪它辦理的文件了。VFS 供給了一組規(guī)范的文件拜訪接口。這些接口以體系調(diào)用的方法,供給給應(yīng)用程序運用。
就拿 cat 命令來說,它首要調(diào)用 open() ,打開一個文件;然后調(diào)用 read() ,讀取文件的內(nèi)容;最終再調(diào)用 write() ,把文件內(nèi)容輸出到控制臺的規(guī)范輸出中:
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ù)是否使用規(guī)范庫緩存,能夠把文件 I/O 分為緩沖 I/O 與非緩沖 I/O。
緩沖 I/O,是指使用規(guī)范庫緩存來加快文件的拜訪,而規(guī)范庫內(nèi)部再經(jīng)過體系調(diào)度拜訪文件。
非緩沖 I/O,是指直接經(jīng)過體系調(diào)用來拜訪文件,不再經(jīng)過規(guī)范庫緩存。
注意,這里所說的“緩沖”,是目規(guī)范庫內(nèi)部完結(jié)的緩存。比方說,你可能見到過,很多程序遇到換行時才真實輸出,而換行前的內(nèi)容,其實便是被規(guī)范庫暫時緩存了起來。
無論緩沖 I/O 還對錯緩沖 I/O,它們最終仍是要經(jīng)過體系調(diào)用來拜訪文件。咱們知道,體系調(diào)用后,還會經(jīng)過頁緩存,來削減磁盤的 I/O 操作。
第二,依據(jù)是否使用操作體系的頁緩存,能夠把文件 I/O 分為直接 I/O 與非直接 I/O。
直接 I/O,是指越過操作體系的頁緩存,直接跟文件體系交互來拜訪文件。
非直接 I/O 正好相反,文件讀寫時,先要經(jīng)過體系的頁緩存,然后再由內(nèi)核或額外的體系調(diào)用,真實寫入磁盤。
想要完結(jié)直接 I/O,需要你在體系調(diào)用中,指定 O_DIRECT 標(biāo)志。假如沒有設(shè)置過,默許 的對錯直接 I/O。
不過要注意,直接 I/O、非直接 I/O,本質(zhì)上仍是和文件體系交互。假如是在數(shù)據(jù)庫等場景中,還會看到,越過文件體系讀寫磁盤的狀況,也便是咱們一般所說的裸 I/O。
第三,依據(jù)應(yīng)用程序是否堵塞本身運轉(zhuǎn),能夠把文件 I/O 分為堵塞 I/O 和非堵塞 I/O
所謂堵塞 I/O,是指應(yīng)用程序履行 I/O 操作后,假如沒有取得呼應(yīng),就會堵塞當(dāng)前線程,天然就不能履行其他任務(wù)。
所謂非堵塞 I/O,是指應(yīng)用程序履行 I/O 操作后,不會堵塞當(dāng)前的線程,能夠持續(xù)履行其他的任務(wù),隨后再經(jīng)過輪詢或許事情告知的方法,獲取調(diào)用的結(jié)果。
比方說,拜訪管道或許網(wǎng)絡(luò)套接字時,設(shè)置 O_NONBLOCK 標(biāo)志,就表明用非堵塞方法拜訪;而假如不做任何設(shè)置,默許的便是堵塞拜訪。
第四,依據(jù)是否等待呼應(yīng)結(jié)果,能夠把文件 I/O 分為同步和異步 I/O
所謂同步 I/O,是指應(yīng)用程序履行 I/O 操作后,要一向比及整個 I/O 完結(jié)后,才干取得 I/O 呼應(yīng)。
所謂異步 I/O,是指應(yīng)用程序履行 I/O 操作后,不必等待完結(jié)和完結(jié)后的呼應(yīng),而是持續(xù)履行就能夠。比及這次 I/O 完結(jié)后,呼應(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)核會再經(jīng)過 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ò)套接字和管道等,它們都經(jīng)過一致的 VFS 接口來拜訪。