自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

磁盤(pán)又雙叒叕滿(mǎn)了,怎么辦?

存儲(chǔ) 存儲(chǔ)軟件
為什么1個(gè)字節(jié)的文件需要占用8個(gè) block 呢, 可以這樣理解, block 為磁盤(pán)存儲(chǔ)的基本的單位,方便磁盤(pán)尋址等(這里說(shuō)的基本單位應(yīng)該是磁盤(pán)物理結(jié)構(gòu)單位例如一個(gè)扇區(qū)/柱面等,對(duì)應(yīng)一個(gè)物理單位)。

[[432229]]

背景

大家好,我是石頭哥。

題目你可能讀不全(沒(méi)事,俺也一樣),特此補(bǔ)充拼音!

[yòu shuāng ruò zhuó]

又雙叒叕

最近有讀者遇到本文一個(gè)神奇的問(wèn)題,來(lái)詢(xún)問(wèn)我為什么。我看了下,確實(shí)是非常經(jīng)典的坑,我在剛畢業(yè)那會(huì)也遇到過(guò),之前文章也分享過(guò),這次重新整理編輯下,再分享給大家。

可以評(píng)論區(qū)說(shuō)說(shuō),你有遇到過(guò)這個(gè)坑嗎?

difference-between-du-and-ls

知道為什么會(huì)有上面的結(jié)果嗎?什么又是稀疏文件?這篇文章將為你揭秘。

磁盤(pán)滿(mǎn)告警

某天收到的自動(dòng)告警短信或者郵件告訴我某機(jī)器上的磁盤(pán)滿(mǎn)了,趕緊登錄機(jī)器查看。

其實(shí),這都應(yīng)該定時(shí)巡檢自動(dòng)化處理的。

第一次出現(xiàn)該問(wèn)題時(shí), 我的處理方式是: 先刪了 /tmp/ 目錄, 空閑出部分空間, 然后檢查下幾個(gè)常用的用戶(hù)目錄。

最終發(fā)現(xiàn)某服務(wù)A的日志文件(contentutil.log)占用了好幾個(gè)十個(gè)大G,詢(xún)問(wèn)相關(guān)開(kāi)發(fā)人員后確定該日志文件不需要壓縮備份, 可直接刪除,于是 rm contentutil.log 之后就天真地認(rèn)為萬(wàn)事大吉了...

rm 文件后,磁盤(pán)空間就釋放了嗎?

磁盤(pán)滿(mǎn)告警,又來(lái)了

然而,大約xx天后,發(fā)現(xiàn)該機(jī)器磁盤(pán)又滿(mǎn)了,驚呼奇怪咋這么快又滿(mǎn)了。

最終發(fā)現(xiàn)是上次 rm contentutil.log 后, 占用好幾十大G的 contentutil.log 一直被服務(wù)A的進(jìn)程打開(kāi)了,rm 后空間并沒(méi)有釋放。

rm 其實(shí)是刪除該文件名到文件真正保存到磁盤(pán)位置的鏈接,此時(shí)該文件句柄還被服務(wù)A打開(kāi),因此對(duì)應(yīng)的磁盤(pán)空間并沒(méi)有被系統(tǒng)回收。

其實(shí)可以理解為 GC 里面的引用計(jì)數(shù), rm 只是減少了引用計(jì)數(shù),并沒(méi)有真正的進(jìn)行釋放,當(dāng)引用計(jì)數(shù)為0的時(shí)候,OS 內(nèi)核才會(huì)釋放空間,供其他進(jìn)程使用。

所以當(dāng)A進(jìn)程停止(文件句柄的引用計(jì)數(shù)會(huì)變?yōu)?)或者重啟后,占用的存儲(chǔ)空間才被釋放(從某種程度上講說(shuō)明該服務(wù)一直很穩(wěn)定, 可以連續(xù)跑很久不出故障~ 微笑臉)。

tip: 如果不知道具體進(jìn)程或文件名的話(huà):lsof | grep deleted,這樣會(huì)查找所有被刪除的但是文件句柄沒(méi)有釋放的文件和相應(yīng)的進(jìn)程,然后再kill掉進(jìn)程或者重啟進(jìn)程即可。

后來(lái),白老板告知可以用修改文件內(nèi)容的方式在不用重啟進(jìn)程的情況下釋放空間。

下面這個(gè)技巧,劃重點(diǎn):

  1. echo "" > filename.log 

du vs ls

前兩天該問(wèn)題又出現(xiàn)了,該服務(wù)A的日志文件(contentutil.log)占用了約7.6G。

應(yīng)該對(duì)服務(wù)日志做 log rotate。

這一次學(xué)聰明了,直接用echo 'hello' > contentutil.log, 然后 df 確認(rèn)磁盤(pán)空間確實(shí)已經(jīng)釋放,心想著這次可以 Happy 了,突然手賤執(zhí)行了下 ls 和 du, 有了以下結(jié)果:

  1. [root@xxx shangtongdai-content-util]# ls -lah contentutil.log 
  2. -rw-r--r--. 1 root root 7.6G Nov  7 19:36 contentutil.log 
  3. [root@xxx shangtongdai-content-util]# du -h contentutil.log 
  4. 2.3M    contentutil.log 

反正我看到這樣的結(jié)果是百思不得其解, 如果你已經(jīng)明確為什么會(huì)產(chǎn)生這樣的結(jié)果呢?

可以明確的是, 這里的 ls 和 du 結(jié)果肯定代表不同的含義,在查閱相關(guān)資料和咨詢(xún)強(qiáng)大的票圈后了解到, 這大概與文件空洞和稀疏文件(holes in 'sparse' files)相關(guān).

ls 的結(jié)果是 apparent sizes, 我的理解是文件長(zhǎng)度,就類(lèi)似文件系統(tǒng)中 file 這個(gè)數(shù)據(jù)結(jié)構(gòu)中的定義文件長(zhǎng)度的這個(gè)字段;

du 的結(jié)果 disk usage,即真正占用存儲(chǔ)空間的大小,且默認(rèn)度量單位是 block。

apparent sizes 和 disk usage 說(shuō)法摘自 man du 中的 --apparent-size 部分。

給出一個(gè)具體的示例:

  1. // Mac OS 10.11.6 (15G1004) 
  2. ➜  _drafts git:(source) ✗ echo -n a >1B.log 
  3. ➜  _drafts git:(source) ✗ ls -las 1B.log 
  4. 8 -rw-r--r--  1 tanglei  staff  1 11  9 00:06 1B.log 
  5. ➜  _drafts git:(source) ✗ du 1B.log 
  6. 8 1B.log 
  7. ➜  _drafts git:(source) ✗ du -h 1B.log 
  8. 4.0K 1B.log 

上面示例中, 文件 1B.log 內(nèi)容僅僅包含一個(gè)字母"a", 文件長(zhǎng)度為1個(gè)字節(jié), 前面的 8 為占用的存儲(chǔ)空間 8 個(gè) block, (ls -s 的結(jié)果跟 du 的結(jié)果等價(jià), 都是實(shí)際占用磁盤(pán)的空間)。

為什么1個(gè)字節(jié)的文件需要占用8個(gè) block 呢, 可以這樣理解, block 為磁盤(pán)存儲(chǔ)的基本的單位,方便磁盤(pán)尋址等(這里說(shuō)的基本單位應(yīng)該是磁盤(pán)物理結(jié)構(gòu)單位例如一個(gè)扇區(qū)/柱面等,對(duì)應(yīng)一個(gè)物理單位)。

而此處的block可以理解為一個(gè)邏輯單位, 且一個(gè)文件除了包括數(shù)據(jù)外, 還需要存儲(chǔ)描述此文件的其他信息, 因此包含1個(gè)字節(jié)的文件實(shí)際在磁盤(pán)中占用的存儲(chǔ)空間不止1個(gè)字節(jié)。

這里借用最近超火的一篇文章的圖示來(lái)解釋?zhuān)?/p>

不得不說(shuō),這篇 “0.2 秒居然復(fù)制了100G文件?” 文章這動(dòng)圖畫(huà)得真好,火是有原因的。不過(guò),遺憾(諷刺)的是最開(kāi)始的原文竟然找不到了(后補(bǔ)充:源自奇伢云存儲(chǔ),鏈接見(jiàn)評(píng)論),各個(gè)文章轉(zhuǎn)載的時(shí)候,都沒(méi)注原文。

磁盤(pán)文件管理基本單位-block

然后讀寫(xiě)的時(shí)候,都用另外一個(gè)結(jié)構(gòu)來(lái)存儲(chǔ)對(duì)應(yīng)的 block 信息。

文件系統(tǒng)inode 和 block 區(qū)

默認(rèn)情況下, Mac中1個(gè)邏輯 block 中是 512 字節(jié), 因此 du -h 結(jié)果是 8 * 512 = 4096 = 4.0K.

If the environment variable BLOCKSIZE is set, and the -k option is not specified, the block counts will be displayed in units of that size block. If BLOCKSIZE is not set, and the -k option is not specified, the block counts will be displayed in 512-byte blocks. (man du)

因此, 通常情況下, ls 的結(jié)果應(yīng)該比 du 的結(jié)果更小(都指用默認(rèn)的參數(shù)執(zhí)行, 調(diào)整參數(shù)可使其表達(dá)含義相同), 然而上面跑服務(wù) A 的機(jī)器上 contentutil.log 的對(duì)比結(jié)果是 7.6G vs. 2.3M, 仍然無(wú)法理解了。

稀疏文件

沿著 man du 可以看到:

although the apparent size is usually smaller, it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like

即因contentutil.log是一個(gè)稀疏文件, 雖然其文件長(zhǎng)度很大, 到7.6G了, 然而其中包含大量的holes并不占用實(shí)際的存儲(chǔ)空間。

下面用一個(gè)具體的例子來(lái)復(fù)現(xiàn)以上遇到的問(wèn)題。注意以下例子為 Linux version 2.6.32 (Red Hat 4.4.7)中運(yùn)行結(jié)果, 且在 Mac 中并不能復(fù)現(xiàn)(后文有指出為什么我的Mac不能復(fù)現(xiàn))。

  1. // 從標(biāo)準(zhǔn)輸入中讀取 count=0 個(gè)block, 輸出到 sparse-file 中,  
  2. // 一個(gè) block 的大小為1k(bs=1k), 輸出時(shí)先將寫(xiě)指針移動(dòng)到 seek 位置的地方 
  3. [root@localhost ~]# dd of=sparse-file bs=1k seek=5120 count=0 
  4. 0+0 records in 
  5. 0+0 records out 
  6. 0 bytes (0 B) copied, 1.6329e-05 s, 0.0 kB/s 
  7. // 所以此時(shí)的文件長(zhǎng)度為: 5M = 5120*1k(1024) = 5242880 
  8. [root@localhost ~]# ls -l sparse-file 
  9. -rw-r--r--. 1 root root 5242880 Nov  8 11:32 sparse-file 
  10. [root@localhost ~]# ls -ls sparse-file 
  11. 0 -rw-r--r--. 1 root root 5242880 Nov  8 11:32 sparse-file 
  12. // 而 sparse-file 占用的存儲(chǔ)空間為 0 個(gè) block 
  13. [root@localhost ~]# du sparse-file 
  14. 0 sparse-file 
  15. [root@localhost ~]# du -h sparse-file 
  16. 0 sparse-file 

此時(shí)若用 vim 打開(kāi)該文件, 用二進(jìn)制形式查看 (tip :%!xxd 可以更改當(dāng)前文件顯示為2進(jìn)制形式), 能看到里面的內(nèi)容全是0. 或者直接用od命令查看2進(jìn)制.

  1. // vim 二進(jìn)制查看 
  2. 0000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................ 
  3. 0000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................ 
  4. .... 
  5. //od -b sparse-file 
  6. 0000000   000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 
  7. 24000000 

實(shí)際上, Sparse 文件是并不占用磁盤(pán)存儲(chǔ)空間的, 那為什么能看到文件里面包含很多0? 因?yàn)楫?dāng)在讀取稀疏文件的時(shí)候, 文件系統(tǒng)根據(jù)文件的 metadata(就是前面所指描述文件的這個(gè)數(shù)據(jù)結(jié)構(gòu))自動(dòng)用0填充[ref Wiki];

Wiki上還說(shuō),現(xiàn)代的不少文件系統(tǒng)都支持 Sparse 文件, 包括 Unix 及其變種和 NTFS, 然而Apple File System(APFS)不支持, 因此我在我的 Mac 上用 du 查看占用空間與 ls 的結(jié)果一致。

  1. // In Mac 
  2. ➜  ~ dd of=sparse-file bs=1k seek=5120 count=0 
  3. 0+0 records in 
  4. 0+0 records out 
  5. 0 bytes transferred in 0.000024 secs (0 bytes/sec) 
  6. ➜  ~ ls -ls sparse-file 
  7. 10240 -rw-r--r--  1 tanglei  staff  5242880 11  9 09:44 sparse-file 
  8. ➜  ~ du sparse-file 
  9. 10240 sparse-file 

以上是用 dd 等命令創(chuàng)建稀疏文件, 也有同學(xué)用 c 代碼實(shí)現(xiàn)了相同的功能。

其實(shí)就是寫(xiě)文件的時(shí)候, 改變下當(dāng)前文件寫(xiě)指針,前面遇到的問(wèn)題就應(yīng)該類(lèi)似。

  1. #include <stdio.h> 
  2. #include <fcntl.h> 
  3. #include <string.h> 
  4.  
  5. int main() { 
  6.     int fd, result; 
  7.     char wbuf[] = "hello"
  8.  
  9.     if ((fd = open("./filetest.log", O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR)) 
  10. )  { 
  11.             perror("open"); 
  12.             return -1; 
  13.     } 
  14.     if ((result = write(fd, wbuf, strlen(wbuf)+1)) < 0) { 
  15.             perror("write"); 
  16.             return -1; 
  17.     } 
  18.     if ((result = lseek(fd, 1024*1024*10, SEEK_END)) < 0) { 
  19.             perror("lseek"); 
  20.             return -1; 
  21.     } 
  22.     if ((result = write(fd, wbuf, strlen(wbuf)+1)) < 0) { 
  23.             perror("write"); 
  24.             return -1; 
  25.     } 
  26.  
  27.     close(fd); 
  28.     return 0; 

以上先將"hello"寫(xiě)入 filetest.log, 然后改變文件指針到1024*1024*10(相當(dāng)于文件長(zhǎng)度這個(gè)字段變大了), gcc 編譯后運(yùn)行結(jié)果文件詳情如下:

  1. [root@localhost ~]# ls -ls filetest.log 
  2. 8 -rw-------. 1 root root 10485772 Nov  9 17:45 filetest.log 
  3. [root@localhost ~]# du  filetest.log 
  4. 8 filetest.log 
  5. [root@localhost ~]# du -h filetest.log 
  6. 8.0K filetest.log 
  7. [root@localhost ~]# ls -lh filetest.log 
  8. -rw-------. 1 root root 11M Nov  9 17:45 filetest.log 
  9. [root@localhost ~]# od -c filetest.log 
  10. 0000000   h   e   l   l   o  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0 
  11. 0000020  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0 
  12. 50000000  \0  \0  \0  \0  \0  \0   h   e   l   l   o  \0 
  13. 50000014 

解釋下結(jié)果: 文件長(zhǎng)度應(yīng)該是 "hello" 加上 "\n" 共6個(gè)字節(jié)*2 = 12, 再加上1024*1024*10個(gè)字節(jié), 即為ls產(chǎn)生的結(jié)果10485772個(gè)字節(jié)約11M。

而du的結(jié)果為8個(gè)block也為8k(這臺(tái)機(jī)器上的block大小與前面的Mac不一樣, 這里是1024)。

Display values are in units of the first available SIZE from --block-size, and the DU_BLOCK_SIZE, BLOCK_SIZE and BLOCKSIZE environment variables. Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set. (du --help)

總結(jié)

總結(jié)一下: 出現(xiàn)以上問(wèn)題說(shuō)明自己對(duì)一些基礎(chǔ)掌握得尚不牢固, 比如

rm 某文件后, 文件占用的磁盤(pán)空間并不是立即釋放,而是其句柄沒(méi)有被任意一個(gè)進(jìn)程引用時(shí)才回收;

ls/du 命令結(jié)果的具體含義;

 

稀疏文件。

 

責(zé)任編輯:武曉燕 來(lái)源: 程序猿石頭
相關(guān)推薦

2017-03-13 16:58:05

戴爾

2024-04-03 15:41:53

服務(wù)器

2018-11-08 17:57:22

華為

2025-02-20 12:00:13

React前端React 19

2023-01-10 11:37:22

Python 庫(kù)PySnooper項(xiàng)目

2018-01-17 16:36:40

Windows 10Windows免費(fèi)升級(jí)

2017-11-21 10:13:11

微軟打印機(jī)補(bǔ)丁

2019-10-12 09:50:46

Redis內(nèi)存數(shù)據(jù)庫(kù)

2020-12-03 06:18:04

磁盤(pán)Docker容器

2023-12-15 09:19:44

百度飛槳文心大模型大模型

2017-08-23 12:55:51

ROOBO

2017-08-23 17:59:57

ROOBO

2020-05-18 13:23:59

寧暢

2021-08-04 15:11:54

網(wǎng)絡(luò)安全數(shù)據(jù)技術(shù)

2019-06-29 14:39:28

Java開(kāi)發(fā)代碼

2023-01-03 11:34:08

數(shù)據(jù)異常波動(dòng)

2022-10-14 08:18:07

Guavaweb應(yīng)用

2019-06-06 15:44:21

人工智能寒冬AI

2021-11-26 09:55:09

微軟漏洞補(bǔ)丁

2023-05-17 18:38:58

宕機(jī)認(rèn)證令牌
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)