[后台]设计合理的幂等方案
2024年4月10日 00:07
幂等的作用 幂等的作用:保证可重入性,防止重复操作导致脏数据出现。使用场景可能有
前端防抖 接口超时重试 消息重试 只能调一次接口,如一个用户只能领一次券 我们的upsert、redis分布式锁、version乐观锁、for update、唯一索引、状态机其实都有幂等的功能,会在请求重复的时候报错
分布式锁:一般用来防止并发操作,可以处理重复操作的问题。可以加在请求处理的最开始 乐观锁:锁住读实体~写实体期间,这期间的任何其他操作都会失败。但自己也可能失败,要处理好失败的回滚逻辑 方案 支持维度 性能 幂等期 判断幂等时机 使用场景 备注 分布式锁 任意 高 加锁期间 请求开始 操作实体 乐观锁 实体id 低 读-写db期间 写db时 修改实体db行 失败需要回滚前面的操作 insert+uk 任意 低 写db之后 写db时 创建实体 失败需要回滚前面的操作 幂等键设计 结论:一定要用有业务语义的幂等键!最好的幂等键组合是entity_id+idem_key的组合
接口维度的幂等:幂等的控制交给上游,由上游保证自己的请求是可以幂等/不被幂等的。比如上游直接传一个md5sum(req)作为幂等键进来(其他常用的包括req里的核心参数、reqid、时间戳、消息id)。我们检测这个幂等键是否存在:
幂等键已存在:直接幂等。问题:下游可能传错了,不幂等的也结果被幂等,比如批量请求、同一个请求里发起多次请求等。幂等应该自己来控制 幂等键不存在:不幂等,这个不会出错 为了避免上面问题的出现,我们可以结合数据库的实体uk做判断。
数据维度的幂等:采用数据库的带业务语义的uniq key+幂等键联合判断。假设uk就是实体的id,幂等键是业务传过来的自定义值。我们去查找幂等键
uk已存在,幂等键不存在:说明用户希望再次操作同一个数据实体,不幂等 uk不存在,幂等键存在:说明用户希望再次操作其他数据实体,不幂等 uk、幂等键都存在:直接幂等 uk、幂等建都不存在:不幂等 1 2 3 4 5 6 7 // 这个例子实现了一个幂等键 // 业务场景:假设我们要设计一个领奖接口,每个用户只能领一次奖品。 // seq: 如果此奖励一个user_id可以重复领取多次,需要用seq标识唯一 // 用户id、奖励id、和seq表达一次幂等 func getIdemKey(userId string, prizeId string, seq string) (uniqueId string){ return fmt.