系统幂等设计

前言

幂等简单的定义:redis

系统中的屡次操做,无论多少次,都应该产生同样的效果,或返回同样的效果。数据库

好比实际的业务请求为建立一个活动,理论上须要根据业务形态开发幂等建立活动的接口,这样在相同参数调用接口屡次建立活动时,只能够建立成功一次。安全

因为查询天生的是幂等请求,因此针对于查询场景能够不作业务角度的幂等约束,查询幂等的约束可能是针对于资源控制,安全防刷,流控来作的。分布式

一个场景

试想有这样一个场景: A系统传递userId和活动Id调用B系统发券,若是B系统发券成功,须要返回A系统本次发券userId和发券code。 因为B系统须要对本身发出去的券进行限制防止超发,因此会根据userId和code创建幂等拦截。 可是A系统的调用次数是不受信的,B系统会对屡次重复的请求作拦截,这样形成一部分A的请求为无效请求,被直接打回。 可是A系统接受B系统的返回值中是须要code的,若是没有收到code,A系统会认为调用B系统失败,进行重试,结果就形成了A系统不停被重试,B系统拦截无效请求,返回默认值,A再重试的死循环。优化

解决这个场景问题有两种方法:设计

  • 在B系统识别到A重复请求时,须要查询流水表,返回已经发送的code,组装参数返回A系统,A系统识别到code,作本地记录,再也不调用B系统发送。
  • A系统调用B系统发券这个逻辑拆分红两个接口,发券接口调用和查询发券记录。

第一种方案明显的缺点在于,针对于重复发送的请求都会转化成一次查询操做,这样无形中加大了对于B系统资源的浪费,同时因为发券接口逻辑中引入了查询逻辑,形成此接口违反了“单一职能原则”,在将来围绕这个接口的新业务逻辑形成的代码修改时,好比容许对同一个用户发送多张券,可能出现潜在的bug问题。code

第二种方案则是我选择的更好的方案,也是更支持的方案,一个接口最好只作一件事,这样一个接口只作发券,同时对于屡次重复发券作请求拦截,没有必要放无效请求到系统核心逻辑中,更没有必要所以引入查询逻辑消耗系统资源。 在调用B系统发券接口由于拦截重复请求,返回重复请求状态码后,系统A调用B系统的查询接口,进行已发送code的查询,这样在使用角度和后期业务迭代角度及系统资源使用和将来优化角度来讲,都存在必定的空间,而不会形成代码复杂度提高引入隐患bug。索引

总结

针对于幂等操做还有以下几种方案:token

  • 删除/修改操做,必定要带入版本号和原始修改参数,万不可直接在下游逻辑中直接i++,i--
  • 为进一步拦截真实数据罗库,须要在数据库表中建立惟一约束,防止由于分布式系统锁问题或数据不一致问题致使拦截不到,这样在DB层创建最后一次兜底策略
  • token机制,能够作相似于页面重复提交的功能,token能够放到redis中,并自带实效
  • 悲观锁/乐观锁,通常分为分布式锁,单机锁,update where
  • 有限状态机,订单系统通常都会设计一个订单状态流转的状态机,表述在不一样状态下的状态变动,只有在上一个状态知足时,才会进行接下来的状态变动,这样保证了状态变动的幂等性
  • 接口调用最好引入来源source,序列号seq等信息,能够用source+seq作惟一索引,也能够将这两个值上报作好监控
  • 监控和开关,为能够更直观的观察系统幂等状况,能够创建对应的监控大盘,及告警配置,这样能够更直观的发现问题,同时配置相应的开关,在发现问题时好比被刷时,经过调控开关及时止损。

相关文章
相关标签/搜索