微服务中的幂等设计

幂等原本是数学运算里的概念,维基百科对其的定义为:

  1. 在某二元运算下,幂等元素是指被自己重复运算(或对于函数是为复合)的结果等于它自己的元素。
  2. 某一元运算为幂等的时,其作用在任一元素两次后会和其作用一次的结果相同。例如,高斯符号便是幂等的。

衍生到微服务领域,幂等指的是使用相同的参数多次调用相同的API,对后端产生的影响是一致的,许多人理解为多次调用返回的结果是一样,这种观点是错误的,连最基本的查询接口也不可能是多次查询返回同样的结果,幂等的侧重点是对后端的影响,并不关心返回的数据。幂等是所有客户端-服务端系统都需要考虑的问题,无论你是C-S还是B-S模式,但在B-S模式下,这个问题更为突出,尤其是近几年流行的微服务架构下,这是因为在微服务模式下,单个应用简单,但服务整体更为复杂,完成一个功能需要走较长的调用链,整体链路可能由不同的语言不同框架实现,每个微服务为了保证服务的质量,常常会对一些不确定的因素(如:网络异常、资源耗尽等)导致的问题进行容错处理,典型措施就是重试。

image

上图是互联网应用中非常精简的调用流程,应该说许多公司的链路远比这个复杂,流程中的每个环节都可能出现重试:

  1. 用户可能会频繁点击按钮
  2. 浏览器在网络不稳定情况下重发请求
  3. 反向代码由于网关响应超时或者网络异常重发到另外一个实例
  4. 网关同样可能因为超时/出错自动调用另外一个service

如果请求只涉及到资源查询,显然调用多次并不会对后端数据发生更改,所以查询类的API天然就是幂等的,但如果这是一个创单接口,我们就不得不考虑幂等的问题,创单过程中会涉及到库存扣减、余额扣减、订单数据入库、消息通知等等修改后端资源的操作,为了防止这类请求重复提交到后端,前端页面通常会在用户点击提交后禁用按钮,后端成功后清空表单跳转到提示页面,对于后端服务来讲,通常会采用以下方式实现幂等:

  1. 数据库唯一约束:通过业务设计,确定几个可以唯一识别订单字段设置为唯一索引,这种方式好处就是简单,代码基本不做改动,缺点也很明显,所以的重复请求要穿透整个链路,一直到数据库才能判重,对链路上资源消耗很大,会给数据库带来巨大的压力,即使服务扩容,TPS也很难上去
  2. MVCC:多版本并发控制方式,操作时带上版本号:update t1 set x=y ,version=version+1 where version=xxx,优点是提升了并发响应能力,实现也简单,缺点是只适用更新接口,还是会将重复请求达到数据库,数据库压力较大
  3. 状态机机制,本质上是MVCC方式的变种:订单有多个业务状态,每次操作数据会带上一个状态,只有在上一个状态匹配的情况下会更新数据,优缺点和MVCC大同小异,但这种机制解决了插入的问题,不仅仅适用在更新接口
  4. Token机制,这是一种非常高效的幂等机制,在性能和功能上都达到很好的效果,接下来我们就详细讨论下这种机制的实现

Token机制的核心就是要求客户端的每次请求里必须携带一个UUID,产生UUID的算法很多,如:雪花算法,ObjectID,常用的开发语言也有对应的实现,即使client生成UUID有困难,也可以调用ID生成器预先生成一批缓存到本地,这里就不一一展开。有了这个UUID,可以在多个环节实现拦截,而且这种判断是非常高效的,几乎都是O(1)的时间复杂度,远比数据库唯一约束判断快,譬如在nginx里,我们可以使用lua获取到请求里的UUID,将该UUID放入leveldb、redis、memcache,下次请求时判断该值是否存在,存在直接返回错误否则放行,如果不是使用nginx或者实施上述方案有困难,可以在网关层实现,对于java语言(其他语言也类似),可以做到透明化处理:在网关里注册Idempotentfilter,该filter提取UUID,同样通过leveldb、redis、memcache等高速缓存判断是否可以放行,显然token方案可以尽早发现和拦截订单,大大降低资源消耗,减少数据库压力,对业务也是透明无浸入,但只依赖token机制显然是有缺陷的:当缓存服务出错ldb文件丢失,redis数据意外清空,memcache意外重启等,会导致我们的UUID标志丢失,这时就需要数据库来兜底,数据库的唯一约束是不可或缺的,当出现这些极端情况时,即使请求达到DB,也不会造成数据重复。

有幂等需求的接口,建议采用token机制实现高效的排除重复请求,当然最终落地式需要结合具体的业务场景.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值