1. 程式人生 > >df -h hang 問題

df -h hang 問題

 

近期陸續碰到幾臺主機 df 卡住的問題, 監控程式由於超時引起相關的警報, 系統環境和 strace df 如下所示:

 

strace 顯示卡在了 /proc/sys/fs/binfmt_misc 狀態中:

 

在 systemd 服務中, 掛載  /proc/sys/fs/binfmt_misc
的只有兩個 unit, 分別為  proc-sys-fs-binfmt_misc.automount
和  proc-sys-fs-binfmt_misc.mount
, 檢視幾臺問題機器系統服務狀態, 僅有 automount 服務啟動:

 

問題機器分別進行過觸發 mount 的操作, 但是沒有進行過  systemctl stop proc-sys-fs-binfmt_misc.mount
操作:

 

檢視snoopy 日誌, unmount 操作由 pid 13573 程序操作, 該 pid 的 sid 為 1, pid 為 1 的程序為  /usr/lib/systemd/systemd --switched-root --system --deserialize 22
, snoopy 行為等同 automount 超時自動 unmount :

 

問題機器的 mount 資訊包含如下, timeout 為 300, 這個是  systemd-219-32


之前版本的預設引數, 實際上在  219-32
版本之前紅帽還未引入超時功能, 所以超過 300s 之後 automount 不會自動進行 unmount 操作, 下面的內容僅有一條 binfmt 資訊, 也意味著兩臺機器中沒有訪問 /proc/sys/fs/binfmt_misc 目錄的行為:

 

備註:問題主機由於在 yum 安裝 perl 依賴的過程中更新了 systemd 到 219-57 新版, 但是沒有做重啟操作, 所以 mount 顯示的 timeout 值還是 300, 重新 reload systemd 或 重啟主機後新版 systemd 生效, timeout 值會變為預設 0.

automount 如何工作

systemd 通過 automount 實現了對檔案系統掛載點進行自動掛載和控制的特性, 在使用者訪問指定目錄的時候, 由 automount 判斷自動進行掛載, nfs, sshfs 等使用較多, 目前為止在 centos7 系統中我們僅發現 binfmt_msic 型別是作業系統需要自動掛載的. 詳見 systemd.automount

原因說明

從上述蒐集資訊來看, 更像是 systemd 認為  proc-sys-fs-binfmt_misc.mount
已經關閉, 不過系統或核心還持有  /proc/sys/fs/binfmt_misc
掛載點, 引起競爭, 這樣 df 在訪問掛載點的時候則一直處於掛起狀態. 這個問題類似 nfs 服務端異常斷掉, client 端直接訪問掛載點也會掛起一樣. 沒有做超時處理則 df 一直處於等待狀態.

詳見:  1534701

觸發條件

由於出現問題之前幾臺問題主機都有 unmount 行為, 所以不能按照下面兩個 bug 來概述我們出現的問題:

1498318

1534701

不過目前已知的觸發條件包含以下兩種方式:

第一種

人為製造異常:

 

在執行第三步的時候 systemd 報以下異常, unmount 操作不能註冊, 而系統核心會繼續持有掛載點, 進而引起 df 卡住. 另外在預設 timeout 為 0 的情況下人為製造的異常不會引起 hang 住:

 

執行  systemctl restart proc-sys-fs-binfmt_misc.automount
即可恢復所有堵住的命令. 另外在 TimeoutIdleSec 為 0 的情況下不會復現此問題, 在 TimeoutIdleSec 大於 0 的情況下, 給 systemd 傳送 kill 訊號的時候會導致 timeout 失效.

第二種

如下日誌:

 

我們以 snoopy 日誌的 umount 操作為出發點, 在 systemd 原始檔中查詢對應行為的觸發條件, 以  systemd-219-31
版本為例, 只有  mount_enter_unmounting
函式進行了  /bin/umount
操作, 詳見  src/core/mount.c
檔案:

 

而  mount_enter_unmounting
函式僅被兩個函式呼叫, 分別為正常 stop 操作的響應函式  mount_stop
和訊號事件處理函式  mount_sigchld_event
:

 

問題主機的 umount 日誌顯示不是正常的 stop 操作, 從整個 systemd 日誌來看 umount 操作更像是屬於  mount_sigchld_event
函式的行為, 即在 systemd 的狀態為  UNMOUNTING
, 或者收到  SIGKILL
,  SIGTERM
訊號的時候, 而系統或核心認為當前狀態為 SUCCESS (f 變數), 在從  /etc/mtab
(mtab 為  /proc/self/mountinfo
的軟鏈) 讀取到 mount 資訊的時候, 當前的重試次數(n_retry_umount) 小於 RETRY_UMOUNT_MAX (32) 的時候則進行一次  mount_enter_unmounting
函式呼叫. 不過問題主機上 df 等命令已經卡住了, 不能保證還會走到這個函式裡, 另外也不明確什麼情況下系統核心會和 systemd 的狀態相反.

這種方式沒有好的重現方法, 不過處理方式應該和第一種一樣, 重啟  proc-sys-fs-binfmt_misc.automount
即可.

解決方式

目前並沒有找到真正的觸發條件, 不過我們認為 df 卡住問題在本質上還是由於 systemd 和 kernel 之間存在競爭而引起的, 導致其它程式訪問掛載點的時候出現 hang 住的現象, 根據  redhat bugzilla
的描述, 只要解決掉 mount 和 automount 過程中可能產生的競爭即可, 我們可以通過關閉  proc-sys-fs-binfmt_misc.automount
釋放已經存在的競爭來解決 df hang 住的問題, 所以整體上包含以下三種解決方式:

 

這幾種方式對應用程式無害, 第一種方式影響最小. 不過我們在排錯的過程中發現了一些其它相關的 bug, 所以採取第二種方式會更穩妥,新版的 systemd 對  1354410
和  1498318
兩個 bug 做了狀態反饋處理, 即便有問題也不會出現 hang 住的現象, 另外預設超時時間為 0, 對程式來講相當於只做了重啟操作, 不過後續的版本可能存在變更的可能, 所以保險起見可以將在  proc-sys-fs-binfmt_misc.automount
配置中指定 TimeoutIdleSec=0 引數值, 避免自動進行 unmount 操作. 最後重啟機器即可; 第三種操作則可能影響其它有 automount 需求的軟體(比如新版本的 postgresql), 不過很多軟體在檢測到沒有啟動 automount 的情況下會進行額外的 mount 操作, 不會有嚴重的影響.

參考連結:

1498318

1534701

1709649

github-5916

github-commit

紅帽知識庫

3346491
與我們的觸發條件不一樣, 並不是重新啟用已經 mask 的 unit 問題引起的, 僅提供了類似問題的解決方法.

其它問題

在查詢根源的過程中發現了幾個相關的問題, 這些問題隨 systemd 版本的變更進行了修復: