生产端可靠性投递
两种解决方案
- 消息落库,对消息状态进行打标
- 消息的延迟投递,做二次检查,回调检查
消息落库
流程图
实现流程
- 把自己的业务数据入库(BIZ DB)
- 发送消息前把消息入库(MSG DB)
- 发送消息到Broker
- 通过异步确认方式监听
- 如果成功到达交换机那么把在MSG DB中的消息状态改成成功发送(流程结束)
- 如果失败,可以选择重发
- 因为网络原因可能一直接收不到来自Broker的应答,那么MSG DB中消息的状态可能一直是未发送
- 使用分布式定时任务,抓取超时消息另做处理(比如重发,重发间隔与次数等问题要处理好)
- 如果重试发送消息多次依然无法投递成功,可以选择把消息状态变为投递失败,然后由补偿系统去抓取投递失败的消息进行其他操作
缺点
- 在高并发场景下DB操作过多
延迟投递
流程图
实现流程
- 业务信息落库(BIZ DB)
- 上游服务发送业务消息
- 上游服务向Callback服务发送延时消息
- 下游服务接受到业务消息
- 下游服务向Callback服务发送消息
- Callback服务接收到下游服务传过来的消息,并进行落库(MSG DB)
- Callback服务接收到上游服务传过来的延时信息,根据信息检查MSG DB是否存在该消息
- 如果存在该消息则流程救赎
- 如果不存在则Callback服务通知上游服务消息没过来,进行重发
消息堆积
消息堆积是一种现象指的是大量消息积压在MQ中
为什么会发生消息堆积
- 生产端重发没有控制好重发次数造成消息堆积
- 生产者生产消息过快,消费者消费速度过慢
如何避免消息堆积
RabbitMQ默认有这个设置vm_memory_high_watermark.relative=0.4,当内存占用达到百分之40的时候它将发出内存警报并阻止所有正在发布消息的连接,一旦清除了内存警报便会恢复正常服务。磁盘也是同理,在rabbitmq.conf中或通过rabbitmqctl均可设置
如果消息已经堆积该如何处理
消费端幂等
幂等性
多次操作结果一致
为什么要做消费端幂等
因为生产端可能因为某种原因将一个消息重发好几次,如果消费端不做幂等性处理那么会让自己的业务处理N次重复数据,可能会出现数据库多条重复数据等情况。
总结下来就是消息可能会被重复消费所以需要做幂等性处理。
主流的幂等性解决方案
- 唯一ID+指纹码(利用数据库主键去重)
- 利用Redis的原子性
唯一ID+指纹码实现幂等性
- 消费端接收到消息后首先到数据库中进行查询(唯一ID+指纹码的主键)
- 如果存在则不作任何处理
- 如果不存在则插入到数据库中,然后进行消费
优点
实现简单
缺点
高并发情况下数据库写入的性能瓶颈
解决方案
根据ID进行分库分表进行算法路由
利用Redis实现幂等性
- 消费端接收到消息后使用setnx命令进行存储
- 如果存储成功了证明这条没有被处理过,消费者可以消费
- 如果失败了则不做任何处理