0.2秒居然復(fù)制了100G文件?
時(shí)間:2021-10-25 14:41:41
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]cp引發(fā)的思考今天同事用?cp?命令,把他給驚到了!背景是這樣的:他用?cp??拷貝了一個(gè)100G的文件,竟然一秒不到就拷貝完成了!用?ls??看一把文件,顯示文件確實(shí)是100G。sh-4.4#?ls?-lh-rw-r--r--?1?root?root?100G?Mar??6?1...
cp 引發(fā)的思考今天同事用?
背景是這樣的:他用?
-rw-r--r--?1?root?root?100G?Mar??6?12:22?test.txt但是copy起來為什么會(huì)這么快呢?sh-4.4#?time?cp?./test.txt?./test.txt.cp
real?0m0.107s
user?0m0.008s
sys?0m0.085s
一個(gè) SATA 機(jī)械盤的寫能力能到 150 M/s (大部分的機(jī)械盤都是到不了這個(gè)值的)就算非常不錯(cuò)了,正常情況下,copy 一個(gè) 100G 的文件至少要 682 秒 ( 100 G/ 150 M/s ),也就是 11 分鐘。實(shí)際情況卻是?
2.0M?./test.txt
再看?
??File:?./test.txt
??Size:?107374182400?Blocks:?4096???????IO?Block:?4096???regular?file
Device:?78h/120d?Inode:?3148347?????Links:?1
Access:?(0644/-rw-r--r--)??Uid:?(????0/????root)???Gid:?(????0/????root)
Access:?2021-03-13?12:22:00.888871000? 0000
Modify:?2021-03-13?12:22:46.562243000? 0000
Change:?2021-03-13?12:22:46.562243000? 0000
?Birth:?-
如果,一個(gè)連續(xù)的大磁盤空間給你使用,你會(huì)怎么使用這段空間呢?直觀的一個(gè)想法,我把進(jìn)來的數(shù)據(jù)就完整的放進(jìn)去。這種方式非常容易實(shí)現(xiàn),屬于眼前最簡單,以后最麻煩的方式。因?yàn)闀?huì)造成很多空洞,明明還有很多空間位置,但是由于整個(gè)太大,形狀不合適(數(shù)據(jù)大?。?,哪里都放不下。因?yàn)槟阋乓粋€(gè)完整的空間。怎么改進(jìn)?有人會(huì)想,既然整個(gè)放不進(jìn)去,那就剁碎了唄。這里塞一點(diǎn),那里塞一點(diǎn),就塞進(jìn)去了。對(duì),思路完全正確。改進(jìn)的方式就是切分,把空間按照一定粒度切分。每個(gè)小粒度的物理塊命名為 Block,每個(gè) Block 一般是 4K 大小,用戶數(shù)據(jù)存到文件系統(tǒng)里來自然也是要切分,存儲(chǔ)到磁盤上各個(gè)角落。圖示標(biāo)號(hào)表示這個(gè)完整對(duì)象的 Block 的序號(hào),用來復(fù)原對(duì)象用的。隨之而來又有一個(gè)問題:你光會(huì)切成塊還不行,取文件數(shù)據(jù)的時(shí)候,還得把它們給組合起來才行。所以,要有一個(gè)表記錄文件對(duì)應(yīng)所有 Block 的位置,這個(gè)表被文件系統(tǒng)稱為inode。寫文件的流程是這樣的:
重點(diǎn):文件 size 只是 inode 里面的一個(gè)屬性,實(shí)際物理空間占用則是要看用戶數(shù)據(jù)放了多少個(gè) block ,沒寫數(shù)據(jù)的地方不用分配物理block塊。這樣的文件其實(shí)就是稀疏文件, 它的邏輯大小和實(shí)際物理空間是不相等的。?所以當(dāng)我們用cp命令去復(fù)制一個(gè)這樣的文件時(shí),那肯定迅速就完成了。
cp
?命令,把他給驚到了!背景是這樣的:他用?
cp
??拷貝了一個(gè) 100 G的文件,竟然一秒不到就拷貝完成了!用?ls
??看一把文件,顯示文件確實(shí)是 100 G。sh-4.4#?ls?-lh-rw-r--r--?1?root?root?100G?Mar??6?12:22?test.txt但是copy起來為什么會(huì)這么快呢?sh-4.4#?time?cp?./test.txt?./test.txt.cp
real?0m0.107s
user?0m0.008s
sys?0m0.085s
一個(gè) SATA 機(jī)械盤的寫能力能到 150 M/s (大部分的機(jī)械盤都是到不了這個(gè)值的)就算非常不錯(cuò)了,正常情況下,copy 一個(gè) 100G 的文件至少要 682 秒 ( 100 G/ 150 M/s ),也就是 11 分鐘。實(shí)際情況卻是?
cp
?一秒沒到就完成了工作,驚呆了,為啥呢?更詭異的是:他的文件系統(tǒng)只有 40 G,為啥里面會(huì)有一個(gè) 100 G的文件呢?同事把我找來,看看這個(gè)詭異的問題。分析文件
我讓他先用?du
?命令看一下,卻只有 2M ,根本不是100G,這是怎么回事?sh-4.4#?du?-sh?./test.txt2.0M?./test.txt
再看?
stat
?命令顯示的信息:sh-4.4#?stat?./test.txt??File:?./test.txt
??Size:?107374182400?Blocks:?4096???????IO?Block:?4096???regular?file
Device:?78h/120d?Inode:?3148347?????Links:?1
Access:?(0644/-rw-r--r--)??Uid:?(????0/????root)???Gid:?(????0/????root)
Access:?2021-03-13?12:22:00.888871000? 0000
Modify:?2021-03-13?12:22:46.562243000? 0000
Change:?2021-03-13?12:22:46.562243000? 0000
?Birth:?-
stat
?命令輸出解釋:- Size 為 107374182400(知識(shí)點(diǎn):單位是字節(jié)),也就是 100G ;
- Blocks 這個(gè)指標(biāo)顯示為 4096(知識(shí)點(diǎn):一個(gè) Block 的單位固定是 512 字節(jié),也就是一個(gè)扇區(qū)的大?。@里表示為 2M;
- Size 表示的是文件大小,這個(gè)也是大多數(shù)人看到的大??;
- Blocks 表示的是物理實(shí)際占用空間;
現(xiàn)實(shí)的存取場景
例如你到火車站使用寄存服務(wù):存行李的時(shí)候,是不是要登記一些個(gè)人信息?對(duì)吧,至少自己名字要寫上??赡苓€會(huì)給你一個(gè)牌子,讓你掛手上,這個(gè)東西就是為了標(biāo)示每一個(gè)唯一的行李。取行李的時(shí)候,要報(bào)自己名字,有牌子的給他牌子,然后工作人員才能去特定的位置找到你的行李劃重點(diǎn):存的時(shí)候必須記錄一些關(guān)鍵信息(記錄ID、給身份牌),取的時(shí)候才能正確定位到。文件系統(tǒng)
回到我們的文件系統(tǒng),對(duì)比上面的行李存取行為,可以做個(gè)簡單的類比;- 登記名字就是在文件系統(tǒng)記錄文件名;
- 生成的牌子就是元數(shù)據(jù)索引;
- 你的行李就是文件;
- 寄存室就是磁盤(容納東西的物理空間);
- 管理員整套運(yùn)行機(jī)制就是文件系統(tǒng);
空間管理
現(xiàn)在思考文件系統(tǒng)是怎么管理空間的?如果,一個(gè)連續(xù)的大磁盤空間給你使用,你會(huì)怎么使用這段空間呢?直觀的一個(gè)想法,我把進(jìn)來的數(shù)據(jù)就完整的放進(jìn)去。這種方式非常容易實(shí)現(xiàn),屬于眼前最簡單,以后最麻煩的方式。因?yàn)闀?huì)造成很多空洞,明明還有很多空間位置,但是由于整個(gè)太大,形狀不合適(數(shù)據(jù)大?。?,哪里都放不下。因?yàn)槟阋乓粋€(gè)完整的空間。怎么改進(jìn)?有人會(huì)想,既然整個(gè)放不進(jìn)去,那就剁碎了唄。這里塞一點(diǎn),那里塞一點(diǎn),就塞進(jìn)去了。對(duì),思路完全正確。改進(jìn)的方式就是切分,把空間按照一定粒度切分。每個(gè)小粒度的物理塊命名為 Block,每個(gè) Block 一般是 4K 大小,用戶數(shù)據(jù)存到文件系統(tǒng)里來自然也是要切分,存儲(chǔ)到磁盤上各個(gè)角落。圖示標(biāo)號(hào)表示這個(gè)完整對(duì)象的 Block 的序號(hào),用來復(fù)原對(duì)象用的。隨之而來又有一個(gè)問題:你光會(huì)切成塊還不行,取文件數(shù)據(jù)的時(shí)候,還得把它們給組合起來才行。所以,要有一個(gè)表記錄文件對(duì)應(yīng)所有 Block 的位置,這個(gè)表被文件系統(tǒng)稱為inode。寫文件的流程是這樣的:
- 先寫數(shù)據(jù):數(shù)據(jù)先按照 Block 粒度存儲(chǔ)到磁盤的各個(gè)位置;
- 再寫元數(shù)據(jù):然后把 Block 所在的各個(gè)位置保存起來,即inode(我用一本書來表示);
- 先讀inode,找到各個(gè) Block 的位置;
- 然后讀數(shù)據(jù),構(gòu)造一個(gè)完整的文件,給到用戶;
inode/block 概念
好,我們現(xiàn)在來看看inode,直觀地感受一下:這個(gè)inode有文件元數(shù)據(jù)和Block數(shù)組(長度是15),數(shù)組中前兩項(xiàng)指向Block 3和Block 11,表示數(shù)據(jù)在這兩個(gè)塊中存著。?你肯定會(huì)意識(shí)到:Block數(shù)組只有15個(gè)元素,每個(gè)Block是4K, 難道一個(gè)文件最大只能是 15 * 4K =? 60 K ? ?這是絕對(duì)不行的!?最簡單的辦法就是:把這個(gè)Block數(shù)組長度給擴(kuò)大!比如我們想讓文件系統(tǒng)最大支持100G的文件,Block數(shù)組需要這么長:(100*1024*1024)/4 =?26214400Block數(shù)組中每一項(xiàng)是4個(gè)字節(jié),那就需要(26214400*4)/1024/1024 =?100M?為了支持100G的文件,我們的Block數(shù)組本身就得100M !?并且對(duì)每個(gè)文件都是如此 !即使這個(gè)文件只有1K!?這將是巨大浪費(fèi)!肯定不能這么干,解決方案就是間接索引,按照約定,把這?15 個(gè)槽位分作 4 個(gè)不同類別來用:- 前 12 個(gè)槽位(也就是 0 - 11 )我們成為直接索引;
- 第 13 個(gè)位置,我們稱為?1 級(jí)索引;
- 第 14 個(gè)位置,我們稱為?2 級(jí)索引;
- 第 15 個(gè)位置,我們稱為?3 級(jí)索引;
為什么cp那么快?
接下來我們要寫入一個(gè)奇怪的文件,這個(gè)文件很大,但是真正的數(shù)據(jù)只有8K:在[0,4K]這位置有4K的數(shù)據(jù)在[1T , 1T 4K] 處也有4K數(shù)據(jù)中間沒有數(shù)據(jù),這樣的文件該如何寫入硬盤?- 創(chuàng)建一個(gè)文件,這個(gè)時(shí)候分配一個(gè) inode;
- 在 [ 0,4K ] 的位置寫入 4K 數(shù)據(jù),這個(gè)時(shí)候只需要 一個(gè) block,把這個(gè)編號(hào)寫到?
block[0]
?這個(gè)位置保存起來; - 在 [ 1T,1T 4K ] 的位置寫入 4K 數(shù)據(jù),這個(gè)時(shí)候需要分配一個(gè) block,因?yàn)檫@個(gè)位置已經(jīng)落到三級(jí)索引才能表現(xiàn)的空間了,所以需要還需要分配出 3 個(gè)索引塊;
- 寫入完成,close 文件;
重點(diǎn):文件 size 只是 inode 里面的一個(gè)屬性,實(shí)際物理空間占用則是要看用戶數(shù)據(jù)放了多少個(gè) block ,沒寫數(shù)據(jù)的地方不用分配物理block塊。這樣的文件其實(shí)就是稀疏文件, 它的邏輯大小和實(shí)際物理空間是不相等的。?所以當(dāng)我們用cp命令去復(fù)制一個(gè)這樣的文件時(shí),那肯定迅速就完成了。
總結(jié)
好,我們?cè)偕钊胨伎枷?,文件系統(tǒng)為什么能做到這一點(diǎn)?- 首先,最關(guān)鍵的是把磁盤空間切成離散的、定長的 block 來管理;
- 然后,通過 inode 能查找到所有離散的數(shù)據(jù)(保存了所有的索引);
- 最后,實(shí)現(xiàn)索引塊和數(shù)據(jù)塊空間的后分配;