问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://m.blog.csdn.net/weixin_44591233/article/details/139687430

在分布式系统中,消息队列的幂等性问题是一个常见的挑战。本文将深入探讨如何通过分布式锁、Token令牌和去重表等技术手段,有效防止消息重复提交和重复消费,保障系统的稳定性和数据一致性。

幂等的类型

在讨论解决方案之前,我们先明确幂等性的两种主要类型:

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

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

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

  • 通常情况下,我们认为消息中间件是一个可靠的组件。这里的可靠性指的是,只要消息被成功投递到了消息中间件,它就不会丢失,至少能够被消费者成功消费一次。这是消息中间件最基本的特性之一,也就是我们通常所说的“AT LEAST ONCE”,即消息至少会被成功消费一遍。

  • 造成问题也很明显,如果消息中间件迟迟收不到客户端消息确认信号,就会让客户端再次消费消息。

怎么解决幂等问题

针对上述两种幂等性问题,我们可以采用以下解决方案:

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

分布式锁是一种常见的防止重复提交的解决方案。具体实现步骤如下:

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

Token令牌

Token令牌机制也是一种有效的防止重复操作的方法。具体流程如下:

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

需要注意的是,这种方法需要两次请求才能完成一次业务操作。

去重表

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

具体实现步骤如下:

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

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

具体流程说明:

  1. 第一次消费时,会先插入一个唯一标识 Key 到 Redis 中,此时必然能插入成功,此时 key 只是插入状态,还没有更新为消费成功状态。
  2. 等到业务消费成功后,再将插入的 key 更新为消费成功状态。
  3. 如果重复发送了消息,Redis中已经存在了对应的key,但是这个key有可能是正在消费状态,也有可能是消费成功状态。这两种情况下都会插入失败,于是接着判断key对应的状态,如果key是消费成功状态,那么直接返回。如果key是正在消费状态,那么将消息发送到重试队列中,等待其他的消费者线程完成消费。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号