服务幂等设计与实践

Posted Alleria Windrunner

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了服务幂等设计与实践相关的知识,希望对你有一定的参考价值。


为什么要聊服务幂等呢?我个人理解吧,在互联网应用烂大街的今天,我们的应用基本上是分布式的,我们的服务集群基本上小则几台节点,大则几十上百台节点,而且都是跨网络调用,那只要涉及到RPC的调用我们就不能保证所有服务一直是可用的,就会有重试操作,这个时候服务如果不是幂等的,不管我们的业务是失败重发或者超时重试都会带来很多麻烦。

举个具体的例子吧,比如我在某支付平台上给朋友转帐,我转帐超时了然后我点击了重试,如果某支付平台的服务没有做幂等,那我朋友可能很高兴因为收到了2笔钱,我就悲剧了。所以我们必须要考虑服务的幂等性。


什么叫幂等

什么叫幂等?我是这么理解的,请求重复执行和执行一次结果相同就叫幂等。即ff(f(x))=f(x),x是参数,f是执行函数/方法/服务。


需要做幂等的服务分类

按照我们之前水平分层的架构,我们哪些服务层需要做幂等呢?我们来分析下:

首先是网关层,需要做服务幂等么?网关层的职责是什么?做一些鉴权之类的操作吧?很显然是不需要的对吧。然后是业务逻辑层,需要做幂等么?业务逻辑层的职责是什么?业务判断和业务执行吧?很显然也是不需要的。其次是数据访问层?需要做么?必须做了吧,因为数据访问层是直接很DB交互了,这里就直接会发生数据的insert、update、delete操作了。最后是DB层,这一层我们通常认为和数据访问层是一起的就没什么好说的了。

当然很多朋友会说我就在网关层做了不好么?请求都不用往下走,可以缩短请求平均响应时间。这个问题仁者见仁智者见智,那你做水平分层干什么吗?干脆所有代码都写在网关层不好么?


需要做幂等的请求分类

我们的请求可以分为2类:

  • 读请求

  • 写请求


那么我们来分析一下,读请求需要做幂等吗?很显然是不需要的。写请求呢?就是我们涉及到需要做insert、update、delete数据库操作的。肯定是需要的对吧?那我们可以得出一个结论,即不会改变数据的操作我们可以不做幂等,会改变数据的操作我们就一定要做幂等。那接下来我们就逐个讨论insert、delete、select、update操作。首先我假设我没有做任何应用层面上的幂等操作。


insert


对于insert操作,当我重复插入数据的时候会出现什么情况?这里我们分两种情况讨论:

  • 自增主键

  • 业务主键


我们拿一个具体的例子来分析:insert into fap_product_info(id, name, type, price, tm_smp)。假如我的id是自增主键会有问题吗?一定会有对不对?因为会产生多条业务数据相同主键不同的数据。那如果是业务主键呢?即我假设对name、type、price建立唯一索引,这样是不是就ok了,即使我id相同,数据库也会报错了。


delete


对于delete操作,当我重复执行的时候会出现什么情况?这里我们也要分两种情况讨论:

  • 相对值删除

  • 绝对值删除


我们拿一个具体的例子分析:

  • delete from fap_product_info where id = 123456;

  • delete top(10) from fap_product_info;


如果是绝对值删除,重复操作两次是不会出现问题的吧。但是如果相对值删除,重复操作就是重复删除多次了咯。


update


对于update操作,当我重复更新数据的时候会出现什么情况呢?这里其实和删除操作是一个道理,我们也需要分两种情况讨论:

  • 相对值删除

  • 绝对值删除

我们拿一个具体的例子分析:

  • update fap_product_info set price = 100 where id = 12345;

  • update fap_product_info set price = price + 100 where id = 12345;


如果是绝对值修改,重复操作也不会有问题吧?但是相对值修改呢?一定会有问题对吧?会重复修改多次。


select 


最后是select操作,其实这个我们不用讨论,因为我们说了不会对数据发生改变的操作我们不用做幂等。


狭义与广义的幂等


以上的所有讨论我们都是基于单库的,这是狭义上的幂等处理。但是在实际的业务场景中,我们的一次请求可能有多个步骤,那这种跨服务、跨事务请求的幂等处理怎么办呢?也就是广义上的幂等处理怎么办呢?其实这个就需要分布式事务来干这个事了,这个后续再聊。


结论


最后我们得出什么结论呢?那就是广义上的幂等处理通过分布式事务来解决,狭义上的幂等处理,对于服务分层来说我们只需要在数据访问层做幂等操作,而对于读写请求幂等处理,insert、delete、select其实我们不用管,为什么呢?因为从规范层面上来讲,insert操作你只要要求必须有唯一业务主键,delete操作在实际业务上是不会被允许的吧?select操作又不需要做幂等处理。那唯一需要处理的是什么操作呢?update操作,但是也很简单,就把相对值修改转换成绝对值修改就ok了。


以上是关于服务幂等设计与实践的主要内容,如果未能解决你的问题,请参考以下文章

基于幂等表思想的幂等实践

基于幂等表思想的幂等实践

「如何设计」具备幂等性的服务

微服务中的幂等设计

接口服务中的幂等性设计和防重保证,详细分析幂等性设计几种实现方法

玩转微服务接口幂等性与安全设计