跳到主要内容

21、RabbitMQ 实战 - RabbitMQ幂等性

1、 概念;

幂等性是指用户对同一操作发起的一次或多次请求的结果都是一致的,不会因为多次点击而产生副作用。举个例子,例如用户购买商品后会进行支付,支付时扣费成功了,在返回支付成功的结果的时候网络异常了,本来应该显示已付款的,但现在显示了未付款,用户再次支付后第二次扣款成功了,返回支付成功,但这时查看流水记录会发现有两条,用户买同一件商品花费了两份的钱,这是不允许的,无论是交易系统自身的bug还是交易系统的网络问题导致重复发送,必须只能扣用户一次钱,多次发送付款请求,扣费还只是扣一次,这就是幂等性。

2、 RabbitMQ幂等性问题;

RabbitMQ把消息发送给消费者消费,消费者消费成功并返回ack消息,但这时候网络中断了,RabbitMQ没有收到ack消息,这就让RabbitMQ误以为消息消费失败了,然后RabbitMQ会重新把该条消息发送给其他的消费者,或者等网络重连后再次发送给该候消费者,这时候就会造成重复消费的问题。

3、 解决思路;

MQ消费者的幂等性的解决一般使用全局ID或者写个唯一标识比如时间戳或者UUID或者订单消费者消费MQ中的消息也可利用MQ的该id来判断,或者可按自己的规则生成一个全局唯一id,每次消费消息时用该id先判断该消息是否已消费过。

4、 消费端幂等性保障思路;

在海量订单生成的业务高峰期,生产端有可能就会重复发送了多条消息,这时候消费端就要实现幂等性,这就意味着我们的消息永远不会被消费多次,即使我们收到了一样的消息。业界主流的幂等性有两种操作:

(1)唯一ID+指纹码机制,利用数据库主键去重

指纹码:我们的一些规则或者时间戳加别的服务给到的唯一信息码,它并不一定是我们系统生成的,基本都是由我们的业务规则拼接而来,但是一定要保证唯一性,然后就利用查询语句进行判断这个id是否存在数据库中,优势就是实现简单就一个拼接,然后查询判断是否重复;劣势就但是在高并发时,如果是单个数据库就会有写入性能瓶颈当然也可以采用分库分表提升性能,但分库分表也不是我们最推荐的方式,最佳方式是利用redis的原子性去实现

(2)Redis的原子性

利用Redis执行setnx命令,天然具有幂等性,从而实现不重复消费。