参考
为什么要使用消息队列
主要考察应用场景及优缺点
优点
- 解耦: 不同服务间的调用
- 异步:不同系统间的调用
- 消峰:秒杀等场景,平时量不高,但在特定时间会有大量请求的情况,配置基础服务器资源,并引入MQ平滑处理请求,亦节约了成本。
缺点
- 可用性降低: 依赖于MQ,若MQ异常,将导致业务异常甚至系统崩溃
- 复杂度提高:需要考虑消息丢失,重复消费等问题
- 一致性问题:多个队列同时操作,部分消费失败的问题,异步的处理返回给用户是成功
消息队列产品比较
如何根据特点进行取舍
- ActiveMQ:万级吞吐量,Java开发,时效性ms级,不怎么维护了,已不建议使用
- RabbitMQ:万级吞吐量,ErLang开发,时效性us级 社区活跃度高,健壮、稳定、易用、跨平台、支持多种语言、文档齐全,对于.net更友好,使用较多;建议中小型项目使用
- KafKa:十万级吞吐量,Scala/Java开发,时效性ms级,性能卓越,分布式可用性高,性能卓越,被大多数日志,大数据领域使用;消费失败不支持重试,使用短轮询方式,实时性取决于轮询间隔时间,支持消息顺序,但是一台代理宕机后,就会产生消息乱序。日志采集等服务建议使用
- RocketMQ:十万级吞吐量,Java开发,时效性ms级,可用性非常高,分布式架构,消息可靠性高,支持10亿级别的消息堆积,不会因为堆积导致性能下降;客户端支持不完善,且阿里的云服务linux只支持http模式访问。大型项目建议使用
消息队列的高可用
- 镜像集群(RabbitMQ):多个节点队列,同步数据,保证数据完整
- 分布式部署(RocketMQ):使用双主双从,保证都有备份
消息丢失问题
消息丢失的原因
- 生产者到MQ,发送过程中丢失
- MQ收到消息,未持久化
- 消费者渠道消息,未处理成功
如何让消息不丢失
- 发送消息后应confirm确认
- 收到消息后持久化
- 消费者消息处理完毕后手动进行ack确认,确认后mq再删除消息
重复消费问题
- 无法避免,消费者取到消息后,可能因网络波动无法收到确认状态,这时消息将会再次被消费
- 消费者应保证消息的幂等性(可以被重复多次消费)
- 添加全局消息ID,消费时根据消息ID添加状态锁,处理成功后清理锁
消息的顺序性
- 分段锁,确保同一业务在一个队列,因先进先出的原理,即可保证消费顺序
分布式事务实现
- 使用本地消息记录消息的消费状态,消费后,回写消息状态,变更本地消息记录表
- 使用定时任务定时查询本地表消费是否完成,未完成则继续发送消息到MQ,达到最终一致性。