写点什么

面试官灵魂暴击:如何保障消息 100% 投递成功及保证消息的幂等性?

作者:冉然学Java
  • 2022 年 7 月 09 日
  • 本文字数:1360 字

    阅读完需:约 4 分钟

面试官灵魂暴击:如何保障消息100%投递成功及保证消息的幂等性?


今天带你们聊一下消息的可靠性传输和幂等性

可能出现消息丢失的情况?


  1. Producer 在把 Message 发送 Broker 的过程中,因为网络问题等发生丢失,或者 Message 到了 Broker,但是出了问题,没有保存下来

针对这个问题,Producer 可以开启 MQ 的事务,如果这个过程出现异常,进行回滚,但是有个很大的问题,你提交一个事务就会阻塞在那,非常影响性能,生产环境肯定不会开启事务,一般都是使用 confirm 机制


  1. Broker 接收到 Message 暂存到内存,Consumer 还没来得及消费,Broker 挂掉了

可以通过持久化设置去解决:(1) 创建 Queue 的时候设置持久化,保证 Broker 持久化 Queue 的元数据,但是不会持久化 Queue 里面的消息; (2) 将 Message 的 deliveryMode 设置为 2,可以将消息持久化到磁盘,这样只有 Message 支持化到磁盘之后才会发送通知 Producer ack。

这两步过后,即使 Broker 挂了,Producer 肯定收不到 ack 的,就可以进行重发。


  1. Consumer 有消费到 Message,但是内部出现问题,Message 还没处理,Broker 以为 Consumer 处理完了,只会把后续的消息发送

这时候,就要关闭 autoack,消息处理过后,进行手动 ack


生产端如何保证可靠性投递?

  1. 保证消息的成功发出

  2. 保证 MQ 节点的成功接收

  3. 发送端收到 MQ 节点(Broker)的确认应答

  4. 完善的消息补偿机制

解决方案

消息落库

  1. 消息落库,对消息状态进行变更,对于高并发环境下数据库压力很大,因为需要写多次数据库

整体流程

  1. 业务数据和消息都进行落库

  2. 生产端发送 message 给 Broker

  3. Broker 给 Confirm 响应返回生产端

  4. 接收到 confirm,对 message 状态更改

  5. 分布式定时任务获取消息的状态

  6. 如果消息不能成功投递,重新进行发送,记录重发次数

  7. 当重发 3 次之后,将状态修改,只能人工进行干预

消息的延迟投递

消息的延迟投递,做二次确认,回调检查。适合高并发环境,减少写库的次数


整体流程

  1. 上游服务首先将业务代码入库,发送 message 给 Broker

  2. 发送第二个延迟确认消息

  3. 下游服务监听消息进行消费

  4. 发送确认消息,这里不是 confirm 机制,而是一条新的消息

  5. 通过回调服务监听这个 confirm 消息,然后把消息进行入库

  6. 回调服务检查到延迟确认消息,会在数据库查询是否有这条消息

  7. 如果没有查到这条消息,回调服务通过 RPC 给一个重新发送命令到上游系统

相比第一种方案,这里减少了一次 message 入库,confirm 机制是消息可靠性投递的一个核心。

RabbitMQ 可能导致出现非幂等性的情况

  1. 可靠性消息投递机制:consumer 回复 confirm 出现网络闪断,producer 没有收到 ack,定时任务轮询可能就会重新发送消息,这样 consumer 就会收到两条消息

  2. MQ Broker 与消费端传输消息的过程出现网络抖动

  3. 消费端故障或异常

kafka 可能出现非幂等性的情况


在 Consumer 端 offset 没有提交的时候,Consumer 重启了,这时候就会出现重复消费的情况

解决方案

唯一 ID+指纹码

整体实现相对简单,需要进行数据库写入,利用数据库主键去重,使用 ID 进行分库分表算法路由,从单库的幂等性到多库的幂等性

  1. 这里唯一 ID 一般就是业务表的主键,比如商品 ID

  2. 指纹码:每次操作都要生成指纹码,可以用时间戳+业务编号+...组成,目的是保证每次操作都是正常的


整体流程

  1. 需要一个统一 ID 生成服务,为了保证可靠性,上游服务也要有个本地 ID 生成服务,然后发送消息给 Broker

  2. 需要 ID 规则路由组件去监听消息,先入库,如果入库成功,证明没有重复,然后发给下游,如果发现库里面有了这条消息,就不发给下游。


转载于:https://mp.weixin.qq.com/s/sBf6cBFSIVwm5Kq2WqQE5Q

用户头像

冉然学Java

关注

还未添加个人签名 2022.07.07 加入

努力学好Java、爱生活、爱旅游的冉冉; 分享自己工作上的经验,交流、共进步、共成长!

评论

发布
暂无评论
面试官灵魂暴击:如何保障消息100%投递成功及保证消息的幂等性?_Java后端_冉然学Java_InfoQ写作社区