MQ介绍
MessageQueue:消息队列,先进先出的数据结构
作用
- 异步:提高系统的响应速度、吞吐量
- 解耦:在生产者和消费者之间搭建桥梁,去除耦合性,减少服务之间的影响,提高稳定性和扩展性
- 削峰:以稳定的系统资源应对突击的流量冲击
官网
https://rocketmq.apache.org/zh/,有安装教程,有社区的Dashboard
如何保证消息不丢失
首先要理清楚哪些环节会造成消息丢失:
- 客户端:生产者发消息到MQ,因为跨网络,可能产生消息丢失
- 服务端:数据还在内存中,未IO到磁盘,系统突然关机等,会造成消息丢失
- 消费端:消费者拉取消息跨网络,可能产生消息丢失
注意:不存在100%不丢失,只存在可靠性和性能的权衡
客户端
网络抖动,客户端以为发送成功,但Broker没收到。解决办法是生产者确认:
- 同步等待,能拿到发送后的响应结果,效率会降低
- 异步回调,也能拿到响应,客户端增加了线程开销
- 失败重试 + 本地兜底:如果发送失败或超时,必须有重试机制(设置重试次数和间隔)
服务端
消息存入了内存但未刷盘,机器宕机导致数据丢失;或主节点挂了,从节点未同步完数据
- 持久化刷盘:必须开启同步刷盘(flush到磁盘)。虽然性能不如异步刷盘,但能保证物理不丢
- 高可用副本机制:利用主从(Master-Slave)或分区副本(Replica)机制。必须等副本同步完成再返回ACK给生产者(即
acks=all)。这样即使Leader宕机,Follower也能顶上,数据不丢
消费端
消费者拉取到消息,先自动提交了Offset(确认位点),但在业务逻辑处理中抛异常或宕机,导致消息丢失
- 关闭自动提交(Auto Commit):这是新手最容易犯的错。一定要手动提交
- 先业务,后确认:严格的顺序是先执行完业务逻辑(如更新数据库),最后再手动提交Offset。只有业务成功,才告诉MQ“这条我消费完了”
- 幂等性兜底:万一业务执行成功,但提交Offset时网络超时,导致MQ重复投递,消费端必须支持幂等(如通过Redis分布式锁或数据库唯一键去重),保证重复消费不影响最终结果