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 來概述我們出現的問題:
不過目前已知的觸發條件包含以下兩種方式:
第一種
人為製造異常:
在執行第三步的時候 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 操作, 不會有嚴重的影響.
參考連結:
紅帽知識庫
3346491
與我們的觸發條件不一樣, 並不是重新啟用已經 mask 的 unit 問題引起的, 僅提供了類似問題的解決方法.
其它問題
在查詢根源的過程中發現了幾個相關的問題, 這些問題隨 systemd 版本的變更進行了修復: