消息如何保证100%的投递成功?
什么是生产端的可靠性投递?
- 保障消息的成功发出;
- 保障MQ节点的成功接收;
- 发送端收到MQ节点(Broker)确认应答;
- 完善消息补偿机制;
生产端可靠性投递常见解决方案
- 消息落库,对消息状态进行打标
将消息存入数据库,记录消息的状态。可以通过轮询不断获取消息的状态,从而保证消息的成功投递。如下图示所示,这样做有一个很严重的问题就是要多次操作数据库,对于一些高并发、对性能要求较高的业务,这种方式是不太合适的。因为频繁操作数据库会带来严重的性能问题。
- 消息的延迟投递,做二次确认,回调检查
生产端会发送两次消息:
第一次:生产端首先会将业务数据存入DB,之后会向MQ发送一个消息,消费端收到消息后发送确认消息(这里的确认消息不是指ack,而是重新编辑发送一条新消息),回调服务监听到确认消息后将消息存入DB;
第二次:在第一条消息发送出去后一段时间,生产端会再发送一条check消息,回调服务监听到check消息后会检查第一条消息的执行情况,如果消息未能按照预期结果执行的话,回调服务会给生产端发送一条指令让生产端重新发送消息;
如下图所示,这种方法可以有效的避免对数据库的频繁操作,从而提高性能;同时业务DB和消息DB之间解耦;
幂等性是什么?
就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等。
消费端幂等性保障:
唯一ID+指纹码机制,利用数据库主键去重
- 好处:实现简单;
- 坏处:高并发下有数据库写入的性能瓶颈;
- 解决方案:利用ID进行分库分表进行算法路由;
update order set count=count+1 ,version==#{oldVersion}+1 where version=#{oldVersion}
select count(1) from order where version = 唯一ID(或)指纹码

