一次線上事故對“本地檔案佇列非同步使用”的思考

duanhao發表於2021-09-09

事故描述

事故現象是部分服務http請求無響應。事故從發生到恢復,接近3個小時,事故過程中重啟應用服務,只能堅持幾分鐘到十幾分鍾,在真正發現問題前透過不斷重啟服務例項來支撐,慶幸的是核心服務沒有出現無響應的事故。

最終分析為AMQ出現故障,現象是MQ客戶端sendMessage後等待響應,但一直在等待,AMQ監控埠ok,控制檯也可以開啟,由於緊急沒有具體分析,直接重啟AMQ服務,切換master,透過驗證服務全部恢復。

這次故障大部分服務都使用了AMQ,但除了一個核心服務沒受到明顯影響外,其他使用AMQ的服務都不同程度的收到了影響,服務不可用。

<strong>
事後透過分析這個核心服務正式使用了本地檔案佇列避免了事故放大,逃過一劫,當時如果這個核心服務也受到影響就可想而知了,事故間期正直商戶業務高峰期,客戶估計要炸了,公司也會受到很大的損失。
</strong>

<strong>
此次事故比較嚴重,就是因為使用了本地檔案佇列有效隔離故障,使得影響面不大。假設(當然不希望發生了)核心業務沒有使用本地檔案佇列來隔離故障,整個下單、收銀服務將不可用,商戶無法營業,損失應該是數量級的。
</strong>

此次事故也證明了我當時的這個架構思路的正確性,主要體現在隔離和降級。

說說這個核心服務使用“本地檔案佇列”

我開發出來這個元件在這個團隊使用一直很穩定效果也很好。

實際上這個團隊使用“本地檔案佇列”的姿勢並不是我期望的,本身使用方法並沒有明顯不妥,只是會延遲訊息的消費,但這中方法可以很好的且有效的隔離故障。

就是在傳送AMQ訊息的方法上新增了@AsyncExecutable,所以在入AMQ前先入隊“本地檔案佇列”,然後“本地檔案佇列”消費者再把訊息生產到AMQ。

圖片描述

這裡正是利用率“本地檔案佇列”的優點,比較可靠,只依賴於本地檔案系統,不會有網路故障的特性,近似不會被阻塞。

在事故分析中,實際上AMQ對該核心服務也受到影響,但由於採用了“本地檔案佇列”作為一級佇列,有效的隔離了對AMQ的網路依賴,所以沒有放大事故。事故中“本地檔案佇列”中訊息被積累,沒有被消費,重啟服務後才被消費,原因後面再分析。

再說說此次事故中服務不可用的原因

  1. AMQ出現故障,現象是MQ客戶端sendMessage後等待響應,但一直在等待。

  2. AMQ Client訊息的生產和Tomcat共用worker執行緒

  3. AMQ Client訊息的生產沒有超時機制

  4. AMQ Client訊息的生產採用同步傳送,非同步傳送有一些問題場景不太合適。

所以基於以上資訊,AMQ訊息的生產阻塞了Tomcat worker執行緒,最終導致worker執行緒被耗光而服務不可用。

在事故中透過執行緒堆疊資訊和Tomcat執行緒使用數統計也確定了執行緒很快被耗光而請求被阻塞。

另一個服務中採用了非同步執行緒池來生產AMQ訊息,但拒絕策略採用了CallerRunsPolicy, 也是執行緒池執行緒很快被耗光而再耗光Tomcat worker執行緒,最終導致服務不可用。

事故產生的原因就是程式碼中沒有有效做網路呼叫的隔離和降級。

上面提到的核心服務也受到影響,參考《》,也是因為“本地檔案佇列”拒絕策略採用了CallerRunsPolicy,最終導致執行緒池執行緒很快被耗光,而使用“本地檔案佇列”消費排程主執行緒,消費排程主執行緒被阻塞而無法消費“本地檔案佇列”訊息並生產到AMQ。但這裡和其他服務不同的是,主業務和AMQ的訊息生產是隔離的,主業務生產訊息到“本地檔案佇列”就返回,並不直接依賴AMQ。

本文中提到了使用本地檔案佇列的隔離姿勢。

後面再介紹使用本地檔案佇列的降級姿勢。



作者:鐵湯
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1343/viewspace-2820526/,如需轉載,請註明出處,否則將追究法律責任。

相關文章