正常執行 30 分鐘後呼叫 sync/fsync 會減慢 IO
使用帶有 ext4混合 SSD的 Ubuntu 14.04 執行 30 分鐘後,我看到許多程序使用 iotop 阻塞了 IO。
這種減速的根本原因可以追溯到 Unix 系統呼叫
sync
。
sync
從終端重複執行可能需要 1 到 2 秒的時間,但只有在 30 分鐘的正常執行時間之後。為了證明這一點,我製作了一個腳本,以秒為單位輸出正常執行時間與執行同步所需的時間,並每秒執行一次:
while true; do cat /proc/uptime | awk '{printf "%f ",$1}'; /usr/bin/time -f '%e' sync; sleep 1; done;
我執行了上面的腳本,等待了大約一個小時(系統處於空閒狀態)並在 gnuplot 中繪製了結果(y = 執行同步的時間,以秒為單位,x = 以秒為單位的正常執行時間):
圖表上升的時間點大約是 1780 年(1780/60 = 大約 30 分鐘)。
除了腳本之外,此時不應將任何內容寫入磁碟,因此在第一次同步後頁面記憶體中應該幾乎沒有任何內容,每個後續同步都將準確寫入正在寫入腳本的內容,大約為 100 字節或所以。
當我檢查
cat /proc/meminfo
臟行(需要保存到磁碟的頁面記憶體中的數據?)和回寫行(HD磁碟緩衝區?)都為零時。我的想法是呼叫會sync
刷新這些磁碟記憶體,但即使這些記憶體中沒有任何內容,它仍然會凍結,所以它會做其他事情嗎?重啟後此問題仍然存在;例如 - 如果我等待 30 分鐘減速然後重新啟動,減速仍然存在。如果我關機然後重新啟動,問題就會消失,直到 30 分鐘後。
另一個好奇心是,當我檢查上圖並放大正在發生減速的區域時,我得到了這個:
波峰和波谷重複 - 從波谷到波谷以 10 秒的間隔發生。
在減速之前,我還執行了 hdparm 測試(
hdparm -t /dev/sda
和):hdparm -T /dev/sda
/dev/sda: Timing cached reads: 23778 MB in 2.00 seconds = 11900.64 MB/sec /dev/sda: Timing buffered disk reads: 318 MB in 3.01 seconds = 105.63 MB/sec
在減速期間:
/dev/sda: Timing cached reads: 2 MB in 2.24 seconds = 915.50 kB/sec /dev/sda: Timing buffered disk reads: 300 MB in 3.01 seconds = 99.54 MB/sec
顯示實際的磁碟讀取沒有受到影響,但記憶體的讀取受到影響,這是否意味著這與系統匯流排有關,而不是 HD?
這是我嘗試過的解決方案:
- 更改 HD 的降速設置(也許 HD 正在進入省電模式?):
hdparm /dev/sda -S252 #(set it to 5 hours before spindown)
- 將文件系統的日誌類型更改為寫回而不是排序,以便我們獲得性能改進 - 這並沒有解決問題,因為它沒有解釋 30 分鐘的無減速正常執行時間,當我嘗試這個時沒有任何變化。
- 禁用 CRON,因為它似乎在 30 分鐘後發生。
- CPU使用率很好並且完全空閒,所以沒有程序可以被指責但是我已經嘗試關閉包括會話管理器(lightdm)在內的所有服務,這沒有任何作用,因為我認為問題是較低級別的。
- 分析任何在 30 分鐘後進入的新程序表明沒有變化——我已經區分了 PS 之前和之後的輸出,沒有任何區別。
這僅在大約 2 週前開始發生,當時沒有安裝任何東西,也沒有進行任何更新。我認為這個問題要低得多,所以非常感謝這裡的一些幫助,因為我一無所知,即使指向正確的方向也會有所幫助。
在有問題的磁碟上啟用了寫記憶體,我也嘗試過禁用寫屏障。HD 上的 SMART 數據表明 HD 本身沒有問題,但是我懷疑 HD 做了一些神秘的事情,因為它在重新啟動後仍然存在。
這是由於為相關驅動器啟用了SMART 數據所致。
禁用 SMART 數據解決了這個問題:
sudo smartctl --smart=off /dev/sda
有趣的是,重新啟用驅動器的 SMART 數據不會使問題再次出現,這向我表明 SMART 處於不一致的狀態(自檢執行時可能崩潰?)並將其關閉然後再次打開以重置該狀態。
據推測,在磁碟旋轉並進入循環後 30 分鐘,它一直在重新執行某種內部自檢;因為這是在硬體層,所以電腦的其餘部分沒有意識到它正在發生,因此我看不到任何程序特別負責 IO 阻塞,也沒有程序佔用資源。
我會在嘗試找出問題所在的同時執行 SMART 自檢,但即使這樣也沒有重置狀態 - 它必須先關閉然後再明確打開。