关于重复消费的一些解决方案

重复消费问题一直是一个热点问题,不管是面试还是实际工作过程中都会遇到,今天我就盘一下这个问题。

1. 重复消费是怎么出现的

重复消费的问题出现的情况有很多,我列举一下常见的吧:

  • 用户重复提交表单。

  • 用户使用软件恶意刷单。

  • 消息由于失败,但是并没有失败,存在重试机制导致重复消费。

  • MQ 中的经典重复消费问题。

2. 那怎么解决呢?

解决重复消费问题,就需要保证一个特性,那就是幂等性,即调用一次请求的结果和调用多次相同请求的结果是一样的。

一般情况下,像查询业务,删除业务这些都是幂等的,而用户下单和退款业务这些不是幂等的。

保证幂等性有以下解决方式:

  1. 用户提交表单后,让提交按钮变为 loading 标志确保不能重复点击,同时跳转到一个提交成功的页面。

  2. 去重,每条消息都有一个唯一标识,通过判断标识是否存在从而去重,这样就能避免处理已经处理过的消息。

  3. 保证接口的幂等性,通过先查再更新的方式修改数据库记录。比如消息有一个唯一标识,那么先去数据库中查找是否有这个标识,如果没有再添加;也可以根据业务来,比如支付业务,先去查对应的支付订单是否为未付款,如果是则进行扣款并更新订单状态。

3. 详细说一下去重

上面提到的解决方式中1,3点都是老生常谈了(个人拙见),我重点说一下去重有哪些方案吧。

1.Redisson 客户端的布隆过滤器

它的底层数据结构是一个 bitmap(位图),里面存放的是二进制0或者1。刚开始全是0,当一个key来了之后先经过3次hash运算,模于数组长度找到对应的数组下标,把对应的0改为1。这样的话,三个数组的位置就能标明一个key的存在。查找的过程也是一样的。

但是它存在一定程度的误判,比如一个 key 过来布隆过滤器判断它存在于 bitmap 中,但是实际上不存在。我们可以通过增加数组的长度或者增加 hash 计算的次数从而减少误判率,但是这也会带来一定的内存和性能开销,实际应用中需要结合业务预估误判率,并且我们需要对误判的情况进行兜底操作,比如查询数据库中是否存在相应的记录。

  • 业务代码

2. 创建自定义注解实现去重

可以自定义一个幂等注解,然后配合 AOP 进行方法拦截,对拦截的请求信息(包括ip+方法名+参数名+参数值)根据固定的规则去生成一个 key,然后调用 redis 的 setnx 方法,如果返回 ok,则正常调用方法,否则就是重复调用了。这样可以保证重复请求接口在一定时间内只会被成功处理一次。至于锁的有效时长要根据业务情况而定的。

  • 创建幂等性注解

  • 获取 IP 的工具类

  • 创建幂等性切面

上述解决调用的重复问题,核心是找到一个唯一的标识,从而判断是否为重复操作。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值