消息队列如何保证幂等【方案篇】

幂等的类型

接口幂等(防止消息重复提交):防止接口重复提交消息

Example:用户在付款的时候,同时点击了多次付款按钮,后端处理了多次相同的扣款请求,结果导致账户被扣了多次钱

消息队列幂等(防止消息重复消费):保障消息队列客户端对相同的消息仅消费一次

通常情况下,我们认为消息中间件是一个可靠的组件。这里的可靠性指的是,只要消息被成功投递到了消息中间件,它就不会丢失,至少能够被消费者成功消费一次。这是消息中间件最基本的特性之一,也就是我们通常所说的
“AT LEAST ONCE”,即消息至少会被成功消费一遍。
造成问题也很明显,如果消息中间件迟迟收不到客户端消息确认信号,就会让客户端再次消费消息

怎么解决幂等问题

分布式锁和 Token 令牌应用于防止接口重复提交,去重表应对于防止消息重复消费场景

分布式锁(避免用户重复访问业务接口)

当用户提交请求时,服务器端生成一个唯一的标识。在处理用户请求之前,服务器尝试获取一个分布式锁。如果成功获取到分布式锁,那么则执行接下来的正常业务逻辑流程。因为锁已经被获取,这样可以确保其他请求无法使用相同的标识,避免重复处理。在请求处理完成后,服务器需要释放分布式锁。

在这里插入图片描述

Token令牌

为了防止重复操作,客户端在第一次调用业务请求之前会发送一个获取 Token 的请求。服务端会生成一个全局唯一的 ID 作为 Token,并将其保存在 Redis 中,同时将该 ID 返回给客户端。
在客户端进行第二次业务请求时,必须携带这个 Token,服务端会验证这个 Token,如果验证成功,则执行业务逻辑并从 Redis 中删除该 Token。
如果验证失败,说明 Redis 中已经没有对应的 Token,表示重复操作,服务端会直接返回指定的结果给客户端。

需要两次请求才能完成一次业务操作。

在这里插入图片描述
在这里插入图片描述

去重表

去重表是指使用 Redis 或者 MySQL 记录已经处理过的请求或操作,以防止重复执行。大部分场景下,大家会使用 Redis 作为去重组件实现。

去重表只是一个说法,其实就是一个 String 的 Key 而已。

具体来说,当客户端发送请求时,服务端会先查询 Redis 去重表来检查该请求是否已经被处理过。如果在存在对应的记录,表示请求已经执行过,服务端可以直接返回,而不再执行重复操作。如果在不存在对应的记录,表示请求是新的,服务端会执行相应的业务逻辑,并在处理完成后将请求的唯一标识(如请求 ID 或标识)添加到 Redis 去重表中,以便后续的重复请求可以被正确识别和处理。

另外,如果消息在消费中抛出异常,消息会触发延迟消费,将消息发送到重试队列 RETRY TOPIC

在这里插入图片描述

说明:

  1. 第一次消费时,会先插入一个唯一标识 Key 到 Redis 中,此时必然能插入成功,此时 key 只是插入状态,还没有更新为消费成功状态
  2. 等到业务消费成功后,再将插入的 key 更新为消费成功状态。
  3. 如果重复发送了消息,Redis中已经存在了对应的key,但是这个key有可能是正在消费状态,也有可能是消费成功状态。这两种情况下都会插入失败,于是接着判断key对应的状态,如果key是消费成功状态,那么直接返回。如果key是正在消费状态,那么将消息发送到重试队列中,等待其他的消费者线程完成消费。
  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值