关于架构:架构师必备系统性解决幂等问题

35次阅读

共计 1221 个字符,预计需要花费 4 分钟才能阅读完成。

要在利用中做到幂等,其实并不难,本文尝试做一个系统性的总结,欢送一起探讨。

什么是幂等

某个操作执行一次,跟执行屡次的成果一样。幂等一词来自于数学中的幂等,即 f(f(x)) = f(x)。

须要保障幂等的场景

查问类的读操作,人造是幂等的,屡次调用不会有副作用。需思考以下几种写操作的状况:

  • 调用上游写接口
  • 写数据库、写 Redis 等
  • 音讯订阅和解决

例子:不能给用户反复发放优惠券、现金处分、告诉等,商家更新商品时不能反复减少或缩小库存。

上面别离探讨这几种状况。

1、调用上游写接口

次要依附上游服务保障幂等。
本服务能做的是,在调上游写接口时不做重试,需设置重试次数为 0。

2、本人服务保障

2.1 基于状态的幂等

这种状况比较简单,只有当满足前置条件时才容许操作,否则不容许更新(例如曾经是终态),间接返回。
例子:订单领取胜利后,不容许反复领取。

2.2 基于惟一键的幂等

幂等 key 的选取

与业务强相干,能够是商品 id、订单 id、用户 id,或者日期等,或者是几个业务字段的组合。

几个例子:

  • 一个用户每天只能领一张优惠券,通过 用户 id+ 优惠券类型 + 日期字符串 即可惟一标识
  • B 端更新库存,商品 id+ 该商品的版本号
  • C 端扣库存,订单 id

值得注意的是,须要辨别新增和批改:批改时的幂等 key 往往须要带上版本号 ,能力辨别是否同一次批改,每次批改对应一个惟一的版本号。

实现形式

MySQL 表中为幂等 key 建设惟一索引:强幂等,例如资金、订单,相对不容许反复解决,当插入反复数据时报错。
不举荐用 Redis 实现幂等,一旦 Redis 出问题,比方节点宕机,可能呈现 2 个 client 同时获取到锁的状况。

MySQL 幂等伪代码:
插入重复记录,捕捉异样,提醒幂等拦挡。

    try {
        // 插入记录
        someDao.create(someRecord);
    } catch (DataIntegrityViolationException e) {
        // 如果是重复记录,返回异样
        return failResponse("幂等拦挡");
    } catch (Throwable t) {
        // 异样解决
        return failResponse("其余异样");
    }

3、音讯订阅和解决

MQ 通常会保障音讯至多发送一次(可能屡次),并且在机器实例重启或发版时,consumer group 会做 rebalance,进而收到反复的音讯。因而,音讯的幂等解决必不可少。

实现形式:
在解决音讯前加上 Redis 锁:如果上锁胜利,则持续解决,否则稍后重试。

  • setnxex,不存在时才设置,时效即为锁的租期,否则疏忽
  • 接下来的业务解决,如果是本身逻辑须要强幂等则应用上述数据库幂等形式,如果全副依赖上游则依赖上游实现幂等

Redis 幂等伪代码:

    // 生成幂等 key
    String redisKey = buildRedisKey();
    // 上 Redis 锁,租期为 leaseTime
    if (redisLock.tryLock(redisKey, leaseTime)) {// 业务逻辑解决} else {// 稍后重试}
    

正文完
 0