背景
- 學生考試上交的場景,我們先將學生數據持久化存儲到mongodb中,就告知學生上交成功。然后通過disruptor消息隊列去處理后續業務邏輯。這里的上交場景會存在高並發的情況。
- 選型disruptor框架的原因是 其強大的單機消息處理能力,我們線上嘗試使用。如果消息處理失敗,則有相應的補償措施。
- 上線之初,對該框架研究不深,已經隱約感覺會有bug在路上。。。
線上問題1-消息丟失
- 學生反饋作業上交提示成功,但老師端沒有收到學生的作業。
排查過程
-
首先通過kibana日志系統,找到了 handler有error日志。那為什么一個學生處理失敗,會導致很多學生作業都消息丟失呢?
最后看到有帖子指出:消費者的handler處理器沒有捕獲異常,導致sequence賦值不對。BatchEventProcessor:151
-
handler增加try/catch異常捕獲,之后上線運行。一切正常。
-
看似完美解決,然又一個bug悄然在路上。
線上問題2-同樣的問題-消息丟失,學生上交作業未成功
-
kibana中未發現 異常日志。
-
本地單測壓測也沒有復現。- 普通的junit模式
-
這個時候應該想到仔細的去看下源碼了。貼一段當時的配置文件的代碼
-
producerType:SINGLE,當時的配置。也沒有深入研究過 SINGLE 和 MULTI 的區別。
-
偶然看到一篇帖子寫到:producerType = SINGLE,在多線程環境中,會導致消息丟失。立馬看到了曙光。
-
通過jemter 壓測50個線程,問題就復現了,消息丟失。
-
此刻感覺找到問題的原因了。通過閱讀 disruptor 源碼:SingleProducerSequencer 和 MultiProducerSequencer 發送消息的區別:MULTI通過CAS操作保證了線程安全。MultiProducerSequencer:112
總結
* 通過以上2個問題,完全是使用方式上的問題:handler異常要捕獲或者設置自定義異常處理器,以及 producerType設置的不對。
* disruptor是典型的 生產者/消費者模型,觀察者模式。每個handler消費者都會由一個線程去消費消息。通過輪詢的方式。核心的處理類是 BatchEventProcessor。
* 接下來要去擼源碼了。