某大廠分佈式存儲程序猿大半夜收到電話報警,某個存儲節點進程和主控節點心跳丟了。
穿着小內褲起來 檢查了一番:網絡
看到業務恢復、故障報警消除後,開始分析root cause。
進程處於func狀態, gdb attach 上去失敗, gcore 也失敗,根本就沒法看到堆棧。
繼續檢查業務日誌:發現故障在磁盤包障後的日誌後出現。
檢查內核日誌:發現有塊nvme 盤掉線了,和pcie root 斷開了!!!分佈式
和廠商及系統部同窗確認了下,出現NVME盤掉線的狀況,短時不影響buffer IO ,隻影響direct IO。ide
這就奇怪了,由於咱們的數據流都是走page cache,並且落盤的時候用pthread, 即使磁盤壞掉了,也只應該影響這個pthread, 不該該致使整個存儲進程上全部其餘的線程,持續週期任務日誌都打印不出來的狀況。工具
究竟是個什麼鬼?測試
現有的日誌和現場已經沒法提供更多線索了,爲了分析這個問題,只有想辦法復現這個現象了。線程
怎麼復現了?既然是壞盤影響IO,那麼我就模擬壞盤吧。
搜索了一卷: 參考 磁盤故障模擬, 發現驗證機器上沒有相關的工具,也沒法安裝包,之好做罷。怎麼辦?日誌
喝了一杯茶回來,想到既然是壞盤影響IO, 那麼就把有IO的地方mock住!code
說幹就幹,把raft 中和業務中數據流上pwrite/pread的地方都替換成無限sleep, 加個開關,啓動後驗證了一遍,一切正常,沒有復現哪一個問題。進程
後來仔細分析了下,不能一直sleep後,應該用while(1)啊,由於碰到磁盤故障,DIO執行到這裏也不會返回,而且不會切換線程。 因而把上面的 sleep換成while。ci
從新編譯執行,打開開關測試 ,仍是一切正常啊!
又分析了一遍,既然NVME盤掉線,直接影響的是DIO,那麼mock的時候:全部相關的這類操做都應該換成while(1)沒法返回,DIO的操做有哪些?
write(O_DIRECT); sync
grep 了一遍,沒有O_DIRECT, 只有sync有幾個,也換成了while(1), 從新啓動,先正常跑了一通,而後把替換sync爲 while(1)的開關打開,沒過幾分鐘,就出現了和線上如出一轍的假死現象。
仔細分析了下咱們的業務,原來在每次元數據更新完都會sync下元數據文件。這個操做在bthread裏,爲了不同時操做這個文件,前面有鎖。而這個操做又是在一個bthread裏, 它作這個又會去拿磁盤基本的鎖,這個鎖又和不少業務線程互斥!!!
這樣一旦這個sync huang住沒法返回,就會致使存儲進程假死!
經過上面的分享能夠看到,分析和模擬磁盤故障,須要知道它的本質影響而後想辦法模擬手影響的地方,這樣才能完全定位根因!