消息队列常面临各种可靠性问题,例如服务宕机、幂等性、消息丢失。
服务宕机
避免服务宕机的最有效解决方案就是部署MQ服务集群,不同的消息服务端有不同集群方案,这个问题笔者抽时间另外起一个专题进行讲解。
幂等性
幂等性的定义
表示任意多次请求执行的结果均与一次请求执行的结果相同,对于一个接口而言,即无论调用多少次,最终得到的结果都是一样的。
消息队列中的幂等性隐患情况
- 消息生产者发送message到MQ服务端的时候,MQ服务端收到消息后需要向生产者表示已接收,但是因为网络波动、网络中断等原因导致确认中断,于是消息生产者再次发送message,导致重复发送,然后导致消息的消费者产生重复消费
- 消息的消费者在接受到message之后,需要向MQ服务端发送确认已接收,但是因为网络波动,宕机等一系列因素导致消费端消费后没有达成向MQ服务端确认收货,导致MQ服务端再次下发消息,消费者收到消息重复消费。
目前主流RabbitMQ、Kafka、RocketMQ并不能完全解决幂等性的问题,只能由我们自己的主程序进行控制。
常规解决方案
消息生产界发送message的时候消息的业务主体要携带一个全局唯一的MessageId,消费者者消费的时候使用redis的setNx(也可以使用Redsisson的lock),在消费端保证不重复消费。
消息丢失
消息丢失的场景
- 生产者发送message给MQ之后,message没有进行持久化,在转发给消费这之前,MQ服务端宕机或重启。
- 人工误删message。
解决方案
在生产者发送给MQ服务端之前,对message进行记录保存,保存方式可以是Log、缓存、数据库等,具体选择视消息重要性考虑。并且消息记录要有三个属性分别是:发送状态(0发送失败 1发送成功)、消费状态(0待消费 1消费成功 2消费失败)、重试次数(记录重试的次数)。
然后使用定时任务检查异常的记录,当发现异常记录的时候则重试,并且重试次数+1,当达到理想次数(一般为3~5次)依然失败的时候,就需要人工干预了,这种做法就是建立消息医院的机制,对有问题的消息进行记录和管理。