關(guān)于文件系統(tǒng),相信大家都不陌生。身為攻城獅的我們幾乎天天都會(huì)與之打交道,但是細(xì)深剖一下,其中又有多少是我們理解深度不夠的呢。那么讓我們一起來(lái)看一下下面這一組 Linux 文件系統(tǒng)相關(guān)的問(wèn)題吧:
1、機(jī)械磁盤(pán)隨機(jī)讀寫(xiě)時(shí)速度非常慢,操作系統(tǒng)是采用什么技巧來(lái)提高隨機(jī)讀寫(xiě)的性能的?
2、touch 一個(gè)新的空文件占用磁盤(pán)空間嗎?占用的話(huà)占用多少?
3、新建一個(gè)空目錄占用磁盤(pán)空間嗎?占用多少?和新建一個(gè)文件相比,哪個(gè)占用的更大?
4、你知道文件名是記錄在磁盤(pán)的什么地方嗎?
5、文件名最長(zhǎng)多長(zhǎng)?受什么制約?
6、文件名太長(zhǎng)了會(huì)影響系統(tǒng)性能嗎?為什么會(huì)產(chǎn)生影響?
7、一個(gè)目錄下最多能建立多少個(gè)文件?
8、新建一個(gè)內(nèi)容大小 1 k 的文件,實(shí)際會(huì)占用多大的磁盤(pán)空間?
9、向操作系統(tǒng)發(fā)起讀取文件 2 Byte 的命令,操作系統(tǒng)實(shí)際會(huì)讀取多少呢?
10、我們使用文件時(shí)要怎么樣來(lái)能提高磁盤(pán)IO速度?
如果你能想也不用想的就回答上來(lái)百分八十的問(wèn)題,那么請(qǐng)關(guān)掉本篇文章吧。如果不能,而且你也像作者一樣對(duì)有窺探操作系統(tǒng)隱私的嗜好,那么就請(qǐng)隨我一起來(lái)探索文件系統(tǒng)的這些有趣的地方,相信理解了這些之后對(duì)我們手中的工作會(huì)有很大的幫助。這篇文章實(shí)驗(yàn)所用文件系統(tǒng)是 ext 系的。
一、磁盤(pán)構(gòu)成及分區(qū)
1、磁盤(pán)物理結(jié)構(gòu)
還是先從最基本的磁盤(pán)物理結(jié)構(gòu)說(shuō)起吧,注意本文只討論機(jī)械磁盤(pán),SSD 不在本文討論范圍之內(nèi)。我們?nèi)祟?lèi)管理任何事物總是習(xí)慣先劃分出一定的結(jié)構(gòu),在此規(guī)則的基礎(chǔ)上進(jìn)行管理。軍隊(duì)分軍、師、旅、團(tuán)和營(yíng)。公司分事業(yè)群、部門(mén)、中心和小組。然后對(duì)于管理磁盤(pán),分磁盤(pán)面、磁頭、磁道、柱面和扇區(qū)。
-
磁盤(pán)面:磁盤(pán)是由一疊磁盤(pán)面組成,見(jiàn)圖。
-
磁頭(Heads):每個(gè)磁頭對(duì)應(yīng)一個(gè)磁盤(pán)面,負(fù)責(zé)該磁盤(pán)面上的數(shù)據(jù)的讀寫(xiě)。。
-
磁道(Track):每個(gè)盤(pán)面會(huì)圍繞圓心劃分出多個(gè)同心圓圈,每個(gè)圓圈叫做一個(gè)磁道。
-
柱面(Cylinders):所有盤(pán)片上的同一位置的磁道組成的立體叫做一個(gè)柱面。
-
扇區(qū)(Sector):以磁道為單位管理磁盤(pán)仍然太大,所以計(jì)算機(jī)前輩們又把每個(gè)磁道劃分出了多個(gè)扇區(qū),見(jiàn)下右圖
本人愛(ài)上 Linux 的一個(gè)原因就是只要你愿意下功夫,你就能把 Linux 的內(nèi)部邏輯徹底鋪開(kāi)來(lái)看,這點(diǎn)比 Windows 要好太多了。Linux 上可以通過(guò) fdisk 命令,來(lái)查看當(dāng)前系統(tǒng)使用的磁盤(pán)的這些物理信息。
以上是我本人的一臺(tái)虛擬機(jī)的磁盤(pán)物理信息??梢钥闯鑫业拇疟P(pán)有 255 個(gè) heads,也就是說(shuō)共有 255 個(gè)盤(pán)面。3263 個(gè) cylinders,也就是說(shuō)每個(gè)盤(pán)面上都有 3263 個(gè)磁道, 63 sectors/track 說(shuō)的是每個(gè)磁道上共有 63 個(gè)扇區(qū)。命令結(jié)果也給出了 Sector size 的值是 512 bytes。那我們動(dòng)筆算一下該磁盤(pán)的大小吧。
255 盤(pán)面 * 3263 柱面 * 63 扇區(qū) * 每個(gè)扇區(qū) 512 bytes = 26839088640 byte。
結(jié)果是 26.8 G,和磁盤(pán)的總大小基本相符(至于fdisk給出的詳細(xì)結(jié)果相差了約4M的大小,筆者也沒(méi)有弄徹底明白,有興趣的讀者可以繼續(xù)研究)。
不過(guò)要注意一點(diǎn)就是上面的盤(pán)面等數(shù)據(jù)是邏輯上的,是物理盤(pán)面映射轉(zhuǎn)化而來(lái)的,這個(gè)轉(zhuǎn)化關(guān)系我現(xiàn)在還沒(méi)搜到特別好的資料。
2、分區(qū)
分區(qū)是操作系統(tǒng)對(duì)磁盤(pán)進(jìn)行管理的第一步,這也是我們?nèi)魏我粋€(gè)計(jì)算機(jī)使用者都非常熟悉的概念。例如Windows下的C、D、E、F盤(pán)。那么請(qǐng)思考一下,
思考:前面的磁盤(pán)的詳細(xì)物理結(jié)構(gòu)已經(jīng)有了,如果讓你把整塊磁盤(pán)分成C、D等分區(qū),你會(huì)怎么分呢?
-
方案一:255 個(gè)盤(pán)面,C 盤(pán)是 0-100 盤(pán)面, D 盤(pán)是 101-200 個(gè)盤(pán)面, ……
-
方案二:3263 個(gè)柱面,C 盤(pán) 0-1000 個(gè)柱面,D 盤(pán) 1001-20001 個(gè)柱面, ……
對(duì)于以上的兩個(gè)方案,你會(huì)選擇哪一種呢??先說(shuō)下磁盤(pán) IO 時(shí)的過(guò)程。
-
第一步,首先是磁頭徑向移動(dòng)來(lái)尋找數(shù)據(jù)所在的磁道。這部分時(shí)間叫尋道時(shí)間。
-
第二步,找到目標(biāo)磁道后通過(guò)盤(pán)面旋轉(zhuǎn),將目標(biāo)扇區(qū)移動(dòng)到磁頭的正下方。
-
第三步,向目標(biāo)扇區(qū)讀取或者寫(xiě)入數(shù)據(jù)。到此為止,一次磁盤(pán) IO 完成。
故單次磁盤(pán) IO 時(shí)間 = 尋道時(shí)間 旋轉(zhuǎn)延遲 存取時(shí)間。
對(duì)于旋轉(zhuǎn)延時(shí),現(xiàn)在主流服務(wù)器上經(jīng)常使用的是1W轉(zhuǎn)/分鐘的磁盤(pán),每旋轉(zhuǎn)一周所需的時(shí)間為60*1000/10000=6ms,故其旋轉(zhuǎn)延遲為(0-6ms)。對(duì)于存取時(shí)間,一般耗時(shí)較短,為零點(diǎn)幾 ms。對(duì)于尋道時(shí)間,現(xiàn)代磁盤(pán)大概在 3-15 ms,其中尋道時(shí)間大小主要受磁頭當(dāng)前所在位置和目標(biāo)磁道所在位置相對(duì)距離的影響。
其實(shí)采用哪一種,最主要看的是那種方式性能更快。因?yàn)橥环謪^(qū)下的數(shù)據(jù)經(jīng)常會(huì)一起讀取,假如采用第一種,那么這樣磁頭就需要在 3000 多個(gè) track 間不停地跳來(lái)跳去,這樣磁盤(pán)的尋道時(shí)間就會(huì)翻倍,磁盤(pán)性能就會(huì)下降。
而對(duì)于方案二,假如對(duì)于磁盤(pán)C,只需要在磁頭在 1-1000 個(gè)磁道間移動(dòng)就可以了,大大降低了尋道時(shí)間。(實(shí)際上分區(qū)并不是從 0 開(kāi)始的,磁盤(pán)的第一個(gè)磁道對(duì)應(yīng)的柱面會(huì)被用來(lái)安裝引導(dǎo)加載程序以及磁盤(pán)分區(qū)表)。所以,方案二的分區(qū)方式可以降低磁盤(pán) IO 時(shí)間中的尋道時(shí)間部分,所以所有的操作系統(tǒng)采用的都是方案二,沒(méi)有用方案一的。
在Linux下使用過(guò)fdisk進(jìn)行分區(qū)的話(huà)可以注意到以下信息。
這充分證明了操作系統(tǒng)是采用方案二的。
回到開(kāi)篇問(wèn)題 1,操作系統(tǒng)是采用什么技巧來(lái)降低隨機(jī)讀寫(xiě)的性能問(wèn)題的呢?操作系統(tǒng)通過(guò)按磁道對(duì)應(yīng)的柱面劃分分區(qū),來(lái)降低磁盤(pán) IO 所花費(fèi)的的尋道時(shí)間 ,進(jìn)而提高磁盤(pán)的讀寫(xiě)性能。
二、目錄與文件
1、引子
好了,磁盤(pán)基礎(chǔ)都說(shuō)完了,那我們正式進(jìn)入主題,開(kāi)始我們 Linux 文件系統(tǒng)相關(guān)的討論吧。文件系統(tǒng)不就是目錄和文件嗎?這二位可是我們熟悉的不能再熟悉的家伙了??赡愦_認(rèn)它不是你的那位熟悉的陌生人么?我先來(lái)來(lái)創(chuàng)建個(gè)空目錄和空文件吧,查看結(jié)果如下圖:
我們都知道第五列顯示的是占用的空間大小,那么我來(lái)提個(gè)幾個(gè)小小的問(wèn)題吧。
-
1)為什么目錄占用的空間是 4096?
-
2)為什么空文件占用的空間卻是 0?
-
3)如果空文件真占用 0 byte 空間,那么該文件的文件名、創(chuàng)建者以及權(quán)限-rw-rw-r—等文件夾相關(guān)的信息都存到哪兒去了?
2、我就不信空文件不占用空間
為了解開(kāi)這個(gè)謎底,需要借助 df 命令。輸入 df –i,
Linux 結(jié)果中紅框位置處顯示的是 inodes 的相關(guān)信息,如果你對(duì) inode 的概念不熟悉,你可以暫時(shí)把它當(dāng)成一個(gè)操作系統(tǒng)秘密管理的一個(gè)家伙,會(huì)占用空間就行了。接下來(lái)我 touch 一個(gè)空的文件后再次 df -i。
雖然前面操作系統(tǒng)告訴我們,一個(gè)新建的空文件占用的空間是 0。但是這個(gè)實(shí)驗(yàn)卻證明操作系統(tǒng)“欺騙”了我們,它消耗掉了一個(gè) inode。那么 inode 的節(jié)點(diǎn)大小是多少呢,使用 dumpe2fs 命令可以幫助我們查看到這個(gè)東東的實(shí)際大小。在輸出的結(jié)果中我們可以找到下面這行。
它告訴我們每個(gè) inode 的大小是 256 Byte。當(dāng)然這個(gè)大小每臺(tái)機(jī)器都會(huì)不一樣,它實(shí)際上是在系統(tǒng)格式化磁盤(pán)的時(shí)候決定的。
好了,開(kāi)篇第二個(gè)問(wèn)題也有答案了。原來(lái)新建一個(gè)空的文件是會(huì)占用磁盤(pán)空間的,實(shí)際占用的是 256 Byte。哦,不,準(zhǔn)確的說(shuō)法應(yīng)該是一個(gè) inode size,具體的值是在格式化時(shí)決定的。
再說(shuō)說(shuō)新建空目錄吧,前面說(shuō)了新建空目錄會(huì)占用4KB的磁盤(pán)空間。那么僅僅如此嗎?我們同樣在新建目錄前后都使用df –i來(lái)監(jiān)視系統(tǒng) inode 的占用。
原來(lái)目錄也是會(huì)占用一個(gè) inode 節(jié)點(diǎn)的,第三個(gè)問(wèn)題也有了答案了,新建一個(gè)空目錄會(huì)占用磁盤(pán)空間 4KB inode size。哦,這個(gè)在你的系統(tǒng)上也不一定是4K,它實(shí)際上一個(gè) block size。同樣在 dumpe2fs 下可以看到。
只不過(guò)我的磁盤(pán)在格式化時(shí)采用的是 4KB 的大小,呵呵!
3、神秘的空目錄的4KB
前面的謎團(tuán)解開(kāi)了,可以作為攻城獅的我對(duì)另外一個(gè)東西產(chǎn)生了好奇心。就是空目錄占用的那 4KB,這些空間是用來(lái)存什么的呢?好神秘呀。cd 到我們新建的目錄下查看。
我們?cè)傩陆▋蓚€(gè)空的文件,再查看下目錄的空間占用情況。
貌似,沒(méi)有什么新發(fā)現(xiàn)。因?yàn)榭瘴募徽加?block,所以這里顯示的仍然是目錄占用的 block,和之前大小沒(méi)有變化。那么我繼續(xù)使用 php 腳本創(chuàng)建 100 個(gè)文件名長(zhǎng)度為 32Byte 的空文件。
這時(shí)我們發(fā)現(xiàn)目錄占用的磁盤(pán)空間變大了,成了 3 個(gè) Block 了。哈哈,這就解答了我們開(kāi)篇的第四個(gè)問(wèn)題,文件名是存在目錄占用的 block 中的。接下來(lái)我又還證明了每個(gè)目錄 block 中能保存的文件名個(gè)數(shù)是和文件名的長(zhǎng)度有關(guān)的(好像有點(diǎn)廢話(huà)的意思,不過(guò)親手證明自己的猜想還是有點(diǎn)小爽的)。我又另外新建了個(gè)空目錄,創(chuàng)建了 100 個(gè)文件名長(zhǎng)度為 32*3 個(gè)空文件,該臨時(shí)目錄占用的磁盤(pán)空間如下:
你可能會(huì)問(wèn)我為什么文件名變成了 3 倍后,占用的 block 數(shù)目為什么沒(méi)有變成 3 倍。其實(shí)Linux文件系統(tǒng)關(guān)于文件的結(jié)構(gòu)體中除了文件名以外,還有其它的一些字段的,文件名變長(zhǎng)3倍不會(huì)導(dǎo)致結(jié)構(gòu)體變大 3 倍的,這點(diǎn)可以參考 Linux 系統(tǒng)內(nèi)核相關(guān)書(shū)籍。
好了,到現(xiàn)在開(kāi)篇問(wèn)題 6 也有了答案了。文件名長(zhǎng)了當(dāng)然會(huì)對(duì)系統(tǒng)性能產(chǎn)生影響,因?yàn)檫@可能會(huì)導(dǎo)致更多的磁盤(pán) IO。很多程序員都喜歡將文件命名為有意義的長(zhǎng)串,使人一看文件名就知道用途。當(dāng)然我沒(méi)說(shuō)這樣不好,但是如果你的文件數(shù)量相當(dāng)大的時(shí)候,你就要考慮你的文件名是否導(dǎo)致你的目錄 block 占用太多了。
占用的空間倒是小事,磁盤(pán)很便宜,但是你得考慮下在目錄下查找文件時(shí)操作系統(tǒng)的感受,操作系統(tǒng)可需要用你你提供的文件名進(jìn)行字符串比較,而且運(yùn)氣不好的話(huà)需要將其名下所有 block 都搞一遍才行啊。(當(dāng)然了,你的文件名長(zhǎng)度不變態(tài),而且數(shù)量沒(méi)有達(dá)到十萬(wàn)數(shù)量級(jí)的話(huà)實(shí)際上這個(gè)開(kāi)銷(xiāo)也不會(huì)太大,但是這個(gè)開(kāi)銷(xiāo)你還是知道的為好)
至于開(kāi)篇問(wèn)題 5,文件名最長(zhǎng)多長(zhǎng)。實(shí)際上Linux操作系統(tǒng)就是為了避免程序員不節(jié)制地使用長(zhǎng)文件名,強(qiáng)加了個(gè)限制,不得超過(guò) 255 byte。
另外,大家有沒(méi)有經(jīng)驗(yàn),在目錄下文件很多的時(shí)候,我們使用ls命令時(shí)會(huì)很慢?,F(xiàn)在大家知道原因了吧,這時(shí)實(shí)際上操作系統(tǒng)在讀取當(dāng)前目錄的所有 block ,如果 block 比較多的話(huà),可能得需要多次 IO 操作才能完成這個(gè)簡(jiǎn)單的 ls 命令。
我在自己的電腦某個(gè)目錄下創(chuàng)建了一 100W 個(gè)空文件,ls 命令 1 分鐘還沒(méi)出結(jié)果,被我 ctrl c 掉了。在自己的項(xiàng)目中可不要這么干,雖然操作系統(tǒng)可以 cache 住你的目錄數(shù)據(jù),使你下次調(diào)用時(shí)會(huì)快很多,但我還是建議你單個(gè)目錄下文件數(shù)目不要過(guò)萬(wàn)。否則你的程序在重啟后首次運(yùn)行時(shí)可能會(huì)出現(xiàn)性能不佳的情況。
好了,回到開(kāi)篇問(wèn)題 7,你有答案了嗎?一個(gè)目錄下最多能建多少個(gè)文件,這個(gè)最多其實(shí)是受限于你目錄所在分區(qū)的 inode 數(shù)量,你有 100W 個(gè) inode,你最多就可以新建 100W 個(gè)文件。但是,上面說(shuō)了,單個(gè)目錄下文件數(shù)量最好不要過(guò)萬(wàn),否則會(huì)帶來(lái)系統(tǒng)性能的問(wèn)題。
4、文件的block
再做個(gè)關(guān)于文件的實(shí)驗(yàn)。我新建了個(gè)空目錄,并在其下新建了個(gè)文件,里面只寫(xiě)了一個(gè)空格數(shù)據(jù),保存后 du 命令顯示如下:
這 8K 里有 4K 是目錄的,也就可以算出操作系統(tǒng)為只包含一個(gè)空格的文件分配了 4KB。其實(shí)文件的 block 比較簡(jiǎn)單的了,不像目錄的 block 里會(huì)存很多文件系統(tǒng)的結(jié)構(gòu)體,文件的 block 里只會(huì)保存文件的數(shù)據(jù)。上面這個(gè)實(shí)驗(yàn)表明,操作系統(tǒng)分配空間時(shí)是以 block 為最小單位。
也就是說(shuō)只要你的文件數(shù)據(jù)不為空,操作系統(tǒng)就至少會(huì)給你分配一個(gè) block 來(lái)存儲(chǔ),直到你超過(guò)了 4KB,操作系統(tǒng)再給你分配下一個(gè) block,就是這樣。所以對(duì)于開(kāi)篇問(wèn)題 8,新建一個(gè)內(nèi)容大小為 1k 的文件,實(shí)際會(huì)占用 1個(gè) block(一般為4k)和一個(gè) inode(一般為256byte)。
其實(shí)文件系統(tǒng)在向磁盤(pán)發(fā)起 IO 請(qǐng)求的時(shí)候,也是以 block size 為單位的。哪怕你只向操作系統(tǒng)發(fā)起讀取文件的 2 Byte,但是操作系統(tǒng)會(huì)一次性給你讀取 4KB 回來(lái)。因此磁盤(pán) IO 真的是很慢,而且我們只要訪(fǎng)問(wèn)了這 2 Byte,確實(shí)很有可能接下來(lái)繼續(xù)訪(fǎng)問(wèn)這 2byte 后面的內(nèi)容,這也就是程序局部性原理,所以操作系統(tǒng)索性一次性就多讀取些回來(lái)了。呵呵,這就是開(kāi)篇問(wèn)題9的答案。
這就像我們?nèi)ス涑?,逛一次真的是很浪費(fèi)時(shí)間,這可要比坑爹的磁盤(pán) IO 也慢許多了。我們總不會(huì)逛了一圈超市就買(mǎi)了一個(gè)蘋(píng)果就回來(lái)了吧,我們肯定會(huì)多買(mǎi)些東西為家里以后的需求準(zhǔn)備著,反正買(mǎi)一堆東西比買(mǎi)一個(gè)蘋(píng)果也沒(méi)多花多少時(shí)間,何樂(lè)為不為呢,就是這個(gè)道理。
再說(shuō)說(shuō)開(kāi)篇問(wèn)題 10,我們攻城獅怎么樣設(shè)計(jì)你的文件能提高一些 IO 速度呢?那就是如果你知道你的要新建的文件大概會(huì)占用多大的空間的話(huà),比如 1M。那么你新建文件時(shí)就順便和操作系統(tǒng)說(shuō)一下,讓它幫你將文件的 size 預(yù)留下來(lái)。這樣實(shí)際上操作系統(tǒng)時(shí)會(huì)盡可能為你分配連續(xù)的 block,這樣你再讀取這個(gè)文件時(shí),磁頭就省去很多尋道時(shí)間了,IO 速度就顯得快多了。
三、寫(xiě)在后面的話(huà)
前面我們說(shuō)的都是基于我自己的文件系統(tǒng),情形是一個(gè) block size 是 4KB,一個(gè) inode size 是 256byte,包括我虛擬機(jī)上的 inode 數(shù)量才只有 140 多萬(wàn)個(gè)。這些值實(shí)際上不是固定的,你完全可以在格式化你的硬盤(pán)的時(shí)候設(shè)置成其它的值。設(shè)置的原則就是看你的硬盤(pán)的容量,以及你的用途。
如果你的文件都是大于 4KB,甚至是幾 M,幾 G 的文件,那么建議你的 block 還是盡可能的大一點(diǎn)吧,這樣 inode 里就能少記幾個(gè)地址。
如果你的文件大部分都是1K以下的,那么確實(shí)使用4K的block會(huì)造成一點(diǎn)點(diǎn)浪費(fèi),如果你的老板對(duì)成本要求異??量痰脑?huà),你可以適當(dāng)考慮把你的 block 設(shè)置得小一點(diǎn)。
另外,要關(guān)注你的文件系統(tǒng)的 inode。操作系統(tǒng)在查看目錄和文件占用的磁盤(pán)空間信息時(shí)把inode節(jié)點(diǎn)的占用給隱藏起來(lái)了,其用意在于為用戶(hù)提供一個(gè)白盒的環(huán)境,把數(shù)據(jù)占用的空間交給我們來(lái)認(rèn)知,而把 inode 信息隱藏起來(lái)為了降低我們理解操作系統(tǒng)的難度。
而實(shí)際上,我們作為非普通用戶(hù)的開(kāi)發(fā)人員應(yīng)該具備這個(gè)知情權(quán)。這個(gè)東東直接關(guān)系到你文件系統(tǒng)能創(chuàng)建文件數(shù)量。否則哪天等你發(fā)現(xiàn)線(xiàn)上機(jī)器磁盤(pán)還剩大把大把的空間,但就是 inode 使用光了,那時(shí)候就只有重新格式化或者遷移服務(wù)器了。這兩個(gè)操作想想都覺(jué)得苦逼啊,還是能避免就盡量避免吧。
思考題:我們大家有個(gè)經(jīng)驗(yàn)就是目錄下小文件太多的情況下,往其它地方拷貝的話(huà),速度會(huì)非常的慢,我們這時(shí)往往會(huì)把目錄壓縮一下再拷貝?,F(xiàn)在你能說(shuō)出這樣做為什么會(huì)快嗎?
最后我想再多說(shuō)一句,這篇九年的時(shí)寫(xiě)的文章現(xiàn)如今看起來(lái)還是很有實(shí)用價(jià)值。
- EOF -
本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀(guān)點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。