消息投递保障方案
消息实际场景无法保证100%投递,极端情况下都会造成数据的丢失,该问题考虑的其实是性能而不是投递保障设计
思路:
1、保障消息成功发送
2、保障MQ节点成功接收消息
3、得到MQ节点的确认应答
4、进行完善的消息补偿机制
常用方案:
1、消息落库,对消息状态进行打标
第一步:消息添加标识入库,封装完Message后再进行二次入库(高并发无需事务),如果入库失败直接进入快速失败方法
第二步:消息投递,brocker 收到消息返回应答
第三步:生产端使用 ConfirmCallback(原生API) 或 ConfirmListener (原生API) 或 ConfirmCallback(RabbitTemplate)对消息进行异步的应答监听,对返回应答成功/失败的消息修改状态并入库,对长时间没有返回应答的(在返回应答阶段遇到网络中断、消息积压【通常会在交换机设置消息过期时间,避免积压】等意外情况导致消息标识一直为入库状态),使用单点或分布式定时任务对库进行扫描,筛选出未应答数据再进重新投递
第四步:设置重新投递消息的次数限制,例如超过三次重新投递依旧返回失败修改其标识值,然后查询出这类消息失败的具体原因
缺点:第一步需要1~2次的数据库写盘操作(Message封装入库必写盘,消息入库存在重新投递情况,该情况不写盘)
消息信心落库,对消息状态进行打标
消息投递方案一演示
2、消息延迟投递,做二次确认 + 回调检查
方案一中消息入库存在数据库磁盘IO瓶颈(可考虑使用AOF的Redis),该方案可避免此情况
第一步:消息进行两次发送,第一次正常发送,第二次是延时发送给指定交换机
第二步:MQ接收消息发送给消费者端,消费者消费第一次正常发送的消息后创建一条消息已经成功消费的消息返回给MQ的指定交换机
第三步:对消息进行监听,获取到成功消费的消息进行入库保存
第四步:监听端获取到延时消息,将延时消息进行解析到库中进行查询,有数据认为消息已成功消费,当入库中找不到消息时认为第一条消息消费失败,调用RPC通信接口通知生产者再次发送数据进行补偿
优点:相较于方案一减少一次写盘操作
案例参考:
消息投递方案二演示