一、如何保障消息的百分百投递成功

1. 什么是生产端的可靠性投递

    1. 保障消息成功发送出去
    1. 保障mq节点成功接受消息
    1. 消息发送端需要收到mq服务的确认应答
    1. 完善的消息补偿机制(百分之百成功,需要该步骤)

2. 解决保障可靠性投递的方案(消息落库)

image.pngimage.png

消息入库打标解决思路(Order_Serve 调用物流服务举例子)

在消息生产者端(也就是订单服务)

正常的链路流程

  • 第一步(该环节调用了操作了二次数据库): 在创建订单的操作的时候,把数据插入订单相关的表中,并且构造调用物流模块的数据消息,把消息插入到消息表中,初始状态为0。

  • 第二步: 把物流消息投递到消息队列中

  • 第三步: 消息队列访问一个确认消息,并且由订单服务来监控 mq Server的确认消息

  • 第四步: 根据收到的确认消息来更新数据库中的消息记录的状态

异常链路流程

第一步(该环节调用了操作了二次数据库): 在创建订单操作的时候,把数据插入到订单相关的表中,并且构造调用物流模块的数据消息,把消息插入到消息表中,初始状态为0

第二步: 把物流消息投递到消息队列中

第三步: 由于网络闪断,导致消费端监控mq服务访问的确认消息没有收到,那么在msg_db中的那条消息的状态永远就是0的状态。 这个时候,我们需要对这种情况下做出补偿。

补偿机制

启动一个分布式的定时任务,不定时去扫描msg_db的这个表,状态为0的消息记录,在这里我们可以根据业务来设置扫描重发规则

规则1: 插入msg_db表中 5 min 后状态还是为0的记录,进行消息重试

规则2: 若重试次数超过五次状态还是为0的话,我们就把消息状态改为2,此时我们需要人工的去确认状态为2的消息是什么原因导致没有成功的。

消息入库打标的缺点:

在第一步的过程中,既插入了业务数据表,也同时插入了消息记录表,进行了二次db操作,在高并发的环境下,这个环境就会造成性能瓶颈。

3. 延时投递,做二次确认检测,回调检测。

image.pngimage.png

二、幂等性以及消息的幂等性

1. 什么是接口的幂等性?

接口的幂等性: 简而言之,就是对接口发起的一次调用和多次调用,所产生的结果都是一致的。

某些接口具有天然的幂等性: 比如长查询接口,不管是查询一次还是多次,返回的结果都是一致的。

1.1 若接口没有保障幂等性,那么就会出现问题

案例一: 比如订单提交的过程中,用户点了一次提交,但是由于网络等与阿奴因,导致后端处理延时,客户就连续点击了多次,在没有幂等性的条件下,那么就会造成订单的重复提交。

解决方案: 在保存订单的时候,根据生成的系统全局唯一ID(这里订单号+业务类型),并且把该唯一ID调用 Redis 的 setnx 命令保存起来,在第一次保存的时候,由于redis中没有该key,那么就会把全局唯一ID进行设置上,此时订单就会保存成功。这个时候若出现前端重复点击按钮,由于第一步已经setnx上了,就会阻止后面的保存。

2. MQ是如何解决幂等性

发送消息的流程
image.png

    1. 第一步: 消息生产者向Mq服务端发送消息
    1. 第二步: mq服务端把消息进行落地
    1. 第三步: 消息服务端向消息生产者发送ack
    1. 第四步: 消息消费者消费消息
    1. 第五步: 消费者发送ack
    1. 第六步: mq服务将落地消息删除

2.1 消息重复发送的原因

上半场消息生产者时用户支付模块,专门是用来扣费的,而下半场的消息消费者服务是会员卡服务,是通过接受扣费服务发送的消息来进行发卡。

由于第三步或者是第五步ack丢失,那么就会导致上游服务重复发送发送消息就会导致扣一次款,发多次卡。

2.2 消息重复发送导致后果

上半场消息生产者时用户支付模块,专门是用来给用户扣费的,而下半场的消息消费者服务是会员卡服务,是通过接受扣费服务发送的消息来进行发卡的。

由于第三步或者是第五步ack丢失,那么就会导致上游服务重复发送消息导致扣一次款,多次发卡。

2.3 mq 服务端是如何保证幂等性的

消息队列的服务中,对每一条消息都会生成一个全局唯一的与业务无关的ID(inner_msg_id),当mq_server接受到消息的时候,先根据inner_msg_id 是否需要重复发送,再决定消息是否落DB,这样保证每条消息都只会落一次DB。

2.4 消费端如何来做到幂等性的?

还是把对每条消息做生成一个唯一性的ID,通过Redis的setnx命令来保证幂等性。