成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

磁盤又雙叒叕滿了,怎么辦?

存儲 存儲軟件
為什么1個字節的文件需要占用8個 block 呢, 可以這樣理解, block 為磁盤存儲的基本的單位,方便磁盤尋址等(這里說的基本單位應該是磁盤物理結構單位例如一個扇區/柱面等,對應一個物理單位)。

[[432229]]

背景

大家好,我是石頭哥。

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

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

又雙叒叕

最近有讀者遇到本文一個神奇的問題,來詢問我為什么。我看了下,確實是非常經典的坑,我在剛畢業那會也遇到過,之前文章也分享過,這次重新整理編輯下,再分享給大家。

可以評論區說說,你有遇到過這個坑嗎?

difference-between-du-and-ls

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

磁盤滿告警

某天收到的自動告警短信或者郵件告訴我某機器上的磁盤滿了,趕緊登錄機器查看。

其實,這都應該定時巡檢自動化處理的。

第一次出現該問題時, 我的處理方式是: 先刪了 /tmp/ 目錄, 空閑出部分空間, 然后檢查下幾個常用的用戶目錄。

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

rm 文件后,磁盤空間就釋放了嗎?

磁盤滿告警,又來了

然而,大約xx天后,發現該機器磁盤又滿了,驚呼奇怪咋這么快又滿了。

最終發現是上次 rm contentutil.log 后, 占用好幾十大G的 contentutil.log 一直被服務A的進程打開了,rm 后空間并沒有釋放。

rm 其實是刪除該文件名到文件真正保存到磁盤位置的鏈接,此時該文件句柄還被服務A打開,因此對應的磁盤空間并沒有被系統回收。

其實可以理解為 GC 里面的引用計數, rm 只是減少了引用計數,并沒有真正的進行釋放,當引用計數為0的時候,OS 內核才會釋放空間,供其他進程使用。

所以當A進程停止(文件句柄的引用計數會變為0)或者重啟后,占用的存儲空間才被釋放(從某種程度上講說明該服務一直很穩定, 可以連續跑很久不出故障~ 微笑臉)。

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

后來,白老板告知可以用修改文件內容的方式在不用重啟進程的情況下釋放空間。

下面這個技巧,劃重點:

  1. echo "" > filename.log 

du vs ls

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

應該對服務日志做 log rotate。

這一次學聰明了,直接用echo 'hello' > contentutil.log, 然后 df 確認磁盤空間確實已經釋放,心想著這次可以 Happy 了,突然手賤執行了下 ls 和 du, 有了以下結果:

  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 

反正我看到這樣的結果是百思不得其解, 如果你已經明確為什么會產生這樣的結果呢?

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

ls 的結果是 apparent sizes, 我的理解是文件長度,就類似文件系統中 file 這個數據結構中的定義文件長度的這個字段;

du 的結果 disk usage,即真正占用存儲空間的大小,且默認度量單位是 block。

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

給出一個具體的示例:

  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 內容僅僅包含一個字母"a", 文件長度為1個字節, 前面的 8 為占用的存儲空間 8 個 block, (ls -s 的結果跟 du 的結果等價, 都是實際占用磁盤的空間)。

為什么1個字節的文件需要占用8個 block 呢, 可以這樣理解, block 為磁盤存儲的基本的單位,方便磁盤尋址等(這里說的基本單位應該是磁盤物理結構單位例如一個扇區/柱面等,對應一個物理單位)。

而此處的block可以理解為一個邏輯單位, 且一個文件除了包括數據外, 還需要存儲描述此文件的其他信息, 因此包含1個字節的文件實際在磁盤中占用的存儲空間不止1個字節。

這里借用最近超火的一篇文章的圖示來解釋:

不得不說,這篇 “0.2 秒居然復制了100G文件?” 文章這動圖畫得真好,火是有原因的。不過,遺憾(諷刺)的是最開始的原文竟然找不到了(后補充:源自奇伢云存儲,鏈接見評論),各個文章轉載的時候,都沒注原文。

磁盤文件管理基本單位-block

然后讀寫的時候,都用另外一個結構來存儲對應的 block 信息。

文件系統inode 和 block 區

默認情況下, Mac中1個邏輯 block 中是 512 字節, 因此 du -h 結果是 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 的結果應該比 du 的結果更小(都指用默認的參數執行, 調整參數可使其表達含義相同), 然而上面跑服務 A 的機器上 contentutil.log 的對比結果是 7.6G vs. 2.3M, 仍然無法理解了。

稀疏文件

沿著 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是一個稀疏文件, 雖然其文件長度很大, 到7.6G了, 然而其中包含大量的holes并不占用實際的存儲空間。

下面用一個具體的例子來復現以上遇到的問題。注意以下例子為 Linux version 2.6.32 (Red Hat 4.4.7)中運行結果, 且在 Mac 中并不能復現(后文有指出為什么我的Mac不能復現)。

  1. // 從標準輸入中讀取 count=0 個block, 輸出到 sparse-file 中,  
  2. // 一個 block 的大小為1k(bs=1k), 輸出時先將寫指針移動到 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. // 所以此時的文件長度為: 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 占用的存儲空間為 0 個 block 
  13. [root@localhost ~]# du sparse-file 
  14. 0 sparse-file 
  15. [root@localhost ~]# du -h sparse-file 
  16. 0 sparse-file 

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

  1. // vim 二進制查看 
  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 

實際上, Sparse 文件是并不占用磁盤存儲空間的, 那為什么能看到文件里面包含很多0? 因為當在讀取稀疏文件的時候, 文件系統根據文件的 metadata(就是前面所指描述文件的這個數據結構)自動用0填充[ref Wiki];

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

  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 等命令創建稀疏文件, 也有同學用 c 代碼實現了相同的功能。

其實就是寫文件的時候, 改變下當前文件寫指針,前面遇到的問題就應該類似。

  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"寫入 filetest.log, 然后改變文件指針到1024*1024*10(相當于文件長度這個字段變大了), gcc 編譯后運行結果文件詳情如下:

  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 

解釋下結果: 文件長度應該是 "hello" 加上 "\n" 共6個字節*2 = 12, 再加上1024*1024*10個字節, 即為ls產生的結果10485772個字節約11M。

而du的結果為8個block也為8k(這臺機器上的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)

總結

總結一下: 出現以上問題說明自己對一些基礎掌握得尚不牢固, 比如

rm 某文件后, 文件占用的磁盤空間并不是立即釋放,而是其句柄沒有被任意一個進程引用時才回收;

ls/du 命令結果的具體含義;

 

稀疏文件。

 

責任編輯:武曉燕 來源: 程序猿石頭
相關推薦

2017-03-13 16:58:05

戴爾

2024-04-03 15:41:53

服務器

2025-02-20 12:00:13

React前端React 19

2018-11-08 17:57:22

華為

2018-01-17 16:36:40

Windows 10Windows免費升級

2023-01-10 11:37:22

Python 庫PySnooper項目

2017-11-21 10:13:11

微軟打印機補丁

2023-12-15 09:19:44

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

2020-12-03 06:18:04

磁盤Docker容器

2019-10-12 09:50:46

Redis內存數據庫

2020-05-18 13:23:59

寧暢

2017-08-23 12:55:51

ROOBO

2017-08-23 17:59:57

ROOBO

2023-01-03 11:34:08

數據異常波動

2019-06-29 14:39:28

Java開發代碼

2021-08-04 15:11:54

網絡安全數據技術

2021-11-26 09:55:09

微軟漏洞補丁

2019-06-06 15:44:21

人工智能寒冬AI

2023-05-17 18:38:58

宕機認證令牌

2022-10-14 08:18:07

Guavaweb應用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 我想看一级黄色毛片 | 欧美另类视频 | 秋霞av国产精品一区 | 免费亚洲网站 | 欧美精品被 | 九九亚洲| 亚洲福利一区二区 | 欧美久久久久久 | 亚洲欧美在线一区 | 免费视频一区二区三区在线观看 | 欧美一区日韩一区 | 99亚洲精品 | 欧美11一13sex性hd | 91精品国产一区二区在线观看 | 麻豆视频在线看 | 黄色成人免费在线观看 | 午夜精品一区二区三区在线视频 | 亚洲国产成人av好男人在线观看 | 精品久久视频 | 久久久久91| 国产美女视频一区 | 91精品国产91久久久久久丝袜 | 狠狠狠干 | 一区二区三区国产精品 | 一级黄色片在线免费观看 | 成人免费观看男女羞羞视频 | 日韩欧美大片 | 久久久久久久久久久蜜桃 | 一本色道精品久久一区二区三区 | 日本视频在线 | 精品成人 | 久久成人精品视频 | 色永久 | 久久精品播放 | 国产精品第2页 | 国产亚洲精品久久久久动 | 欧美久久久久久久 | 国内精品久久精品 | 日本精品视频 | 国产精品久久 | 欧美日韩综合一区 |