背景
- 学生考试上交的场景,我们先将学生数据持久化存储到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。
* 接下来要去撸源码了。