左耳听风_045_44_弹力设计篇之幂等性设计

你好,我是神浩网名猪耳朵house.那今天呢我们来学习密冷性设计。

所谓密冷性设计呢,就是说一次请求和多次请求,某一个资源应该具有同样的副作用。

那用数学的语言来表达呢就是FX等于FFX.比如说求绝对值的函数,ABSX的绝对值呢就等于x的绝对值的绝对值。

那说白了呢就是我们把系统解耦隔离之后,服务间的调用可能会有三个状态。

嗯,一个呢是成功,一个是失败,一个是超时。

那前两个都是明确的状态,而超时呢则是完全不知道是什么状态。

比如说超市原因是网络传输丢包的问题,那可能是请求的时候就没有请求到啊,也有可能是请求到了,但是返回结果的时候呢,没有正常返回等等情况。

于是呢我们就完全不知道下游系统是否受到了请求。,受到了请求,是否处理了成功或者失败的状态,在返回时是否遇到了网络问题。

总之呢,请求方完全不知道是怎么回事儿。

我再来举几个例子。

那第一个例子,订单创建的接口,那第一次调用超时了,然后调用方重试了一次,那是否会多创建一笔订单呢?那第二个例子,订单创建的时候啊,我们需要去扣减库存。

那这个时候接口发生到超时调用方重试了一次,那是否会多扣一次库存呢?那第三个例子,那这笔订单开始支付,在支付请求发出之后,服务端发生了扣钱的操作。

那接口响应超时了,调用方又重试了一次,那是否会多扣一次钱呢?因为系统超时了,调用方重试一下,就会给我们的系统带来不一致的副作用。

在这种情况下呢,一般会有这样两种处理方式。

那一种呢是需要下游系统提供相应的查询接口。

上游系统在tam out之后去查询一下。

那如果查到了啊,就表明已经做了成功了啊,就不用做了,失败了呢就走失败流程。

那另一种呢是通过幂等性的方式,也就是说呢,把这个查询操作交给下游系统。

我上游系统只管重试,让下游系统来保证一次和多次请求的结果是一样的。

那对于第一种方式呢,需要对方提供一个查询接口来做配合。

而第二种方式呢,需要下游的系统提供支持,密等性的交易接口,要做到密等性的交易接口啊,需要有一个唯一的标志来标志,交易是同一笔交易。

而这个交易ID由谁来分配是一件比较头疼的事儿。

因为这个标志需要做到全局唯一。

那如果由一个中心系统来分配,那么每一次交易呢都需要去找那个中心系统。

那这样呢就增加了程序的性能开销。

如果由上游系统来分配呢,那就有可能出现ID分配重复的问题。

因为上游系统可能会是一个集群,他们会同时承担相同的工作。

那为了解决分配冲突的问题,我们需要使用一个不会冲突的算法,比如使用UUID这样冲突非常小的算法。

但是UUID的问题就在于,它的字符串占用的空间比较大,所以呢效率呢非常低。

生成的ID太过于随机啊,完全不是给人读的,而且呢还没有递增。

如果要按照前后顺序排序的话,基本不可能。

那对于全局为EID的算法呢,在这里呢我介绍一个twitter的开源项目。

Snow flake,它是一个分布式ID的生成算法。

那它的核心思想呢就是产生一个long型的ID啊,你可以参考文中的这个示意图。

那其中呢有四十一个比特位作为毫秒数,大概可以用六十九点七年。

那接下来十个比特位呢作为机器编号,那其中五位是数据中心,五位是机器ID.那这样呢一共支持一千零二十四个实例。

那最后十二个比特位呢作为毫秒内的序列号,那一毫秒呢可以生成四千零九十六个序号。

那其他的像REDIS或者mango DB的全局ID生成呢,都和这个算法大同小异。

我在这里呢就不多说了,你可以根据实际情况加上业务的编号。

那接下来呢我们来谈谈幂等性的处理流程。

所谓密等性的处理流程呢,说白了就是要过滤一下已经收到的交易。

要做到这个事儿呢,我们需要一个存储来记录收到的交易。

于是呢当收到交易请求的时候,我们就会到这个存储中去查询。

如果查到了,那么就不再做查询了。

并且把上次做的结果返回。

那如果没有查到呢,我们就把这个请求ID给记录下来。

我在文中呢把这个流程画了出来。

但是呢这个流程有个问题,因为绝大多数请求应该都不会是重新发过来的。

所以让百分之百的请求都到这个存储里去查一下,会导致处理流程呢变得很慢。

所以呢最好是让这个存储出现冲突的时候直接报错。

也就是说呢,我们收到交易请求之后,直接去存储里记录这个ID.那如果出现ID冲突的异常,那么我们就知道这个之前啊已经有人发过来了,所以呢就不用再做了。

那对于更新的场景来说呢,如果只是状态更新,可以使用文中这个方式。

如果出错了,要么是非法操作,要么是已经被更新了,要么呢是状态不对。

总之呢多次调用是不会有副作用的那当然呢网上还有MVCC,通过使用版本号等其他方式。

但是我觉得这些都不标准,我们希望有一个标准的方式来做这个事儿。

所以呢最好还是用一个ID.因为我们的密等性服务也是分布式的,所以呢就需要这个存储也是共享的那这样呢每个服务就变得没有状态了。

但是这个存储呢就成为了一个非常关键的依赖,它的扩展性和可用性呢也成了非常关键的指标。

你可以使用关系性数据库啊或者key value的NO sql来构建这个存储系统。

在最后呢我们来谈一谈HTTP的密冷性HTTP的的方法用于获取资源,它不应该有副作用。

所以呢是幂等的。

比如get一个银行账户的网址,就不会改变资源的状态。

不论是调用一次还是n次啊,都没有副作用。

请注意,我这里强调的是一次和n次具要相同的副作用,而不是每次get的结果相同。

比如说我get一个新闻网址,那这个HTB请求呢可能会每次都得到不同的结果,但是它本身呢并没有产生任何副作用,所以呢是满足密等性的那ATP head方法和get本质呢是一样的。

它们的区别呢在于head不含有呈现术语,而仅仅是ATP头信息,它不应该有副作用,所以呢也是密等的。

有的人可能觉得这个方法没什么用啊,其实不是这样的。

我们想象一个业务情景啊,我想要判断某个资源是否存在。

那我们呢通常就使用get,但如果这里使用head呢,那意义呢会更加明确。

也就是说呢,head方法可以用来做碳活,使用。

Htb options呢主要用于获取当前UIL所支持的方法。

那所以呢也是逆等的。

如果请求成功了,那它的HTB响应头中呢会包含一个名字叫alouad header.它的值呢是所支持的方法,比如get和post HTP. Delete的方法呢用于删除资源啊,它是有副作用的,但是它呢也应该满足密等性。

比如delete论坛中一条帖子的网址,那调用一次和n次对于系统产生的副作用呢是相同的。

所以呢调用者可以多次调用或者刷新页面,而不担心引起错误。

Htp post方法呢用于创建资源所对应的URI,并非创建资源的本身,而去执行创建动作的操作者啊,它有副作用,不满足密冷性,比如post一个论坛的网址。

那它的语义呢,是在这个论坛下创建一篇帖子。

那HTP响应中呢,应该包含帖子的创建状态和帖子的UI.两次相同的pos请求呢会在服务器端创建两份资源,它们具有不同的URI.所以pos方法呢是不具备密等性的HTTP. Put方法呢用于创建或更新操作,所对应的URI呢是要创建或更新资源本身啊是有副作用的,但是它呢应该满足密等性。

比如put一条帖子的网址。

那它的语义呢是创建或更新这个帖子对同一URI进行多次的的副作用呢和一次的是相同的。

所以呢pupuput的方法是具有密等性的,所以对于pos方式呢很可能会出现多次提交的问题。

就好比我们在论坛中发帖的时候,有时候因为网络有问题呢,可能会对同一篇帖子出现多次提交的情况。

所以一般密等性的设计呢会这样的。

首先呢在表单中需要隐藏一个token.那这个token呢可以是前端生成的一个唯一的ID啊,用于防止用户多次点击了表单提交按钮,导致后端受到了多次请求啊,却不能分辨是否是重复的提交。

那这个token呢是表单的唯一标志。

那这种情况呢其实是通过前端生成ID的方式,把post变成了put.然后呢,当用户点击提交之后,那后端呢会把用户提交的数据和这个token保存在数据库中。

那如果有重复提交呢,那么数据库中的token呢会做排他限制啊,从而做到密等性。

那当然呢更为稳妥的做法是后端成功之后,向前端返回三零二跳转,把用户的前端页跳转到get请求,把刚刚pos的数据呢给展示出来。

那如果是web上的那最好呢还要把之前的表单设置成过期。

那这样用户呢就不能通过浏览器后退按钮来重新提交。

那这个模式呢又叫做PRG模式。

好了,我们来总结一下今天分享的主要内容。

首先呢幂等性的含义是一个调用被发送多次所产生的副作用和被发送一次所产生的副作用呢是一样的。

而服务调用呢有三种结果,成功失败和超时。

那其中呢超时是我们需要解决的问题。

那解决手段呢可以是超时之后查询调用结果,也可以是在调用的服务中呢实现密冷性。

那为了在分布式系统中实现幂等性呢,我们需要实现全局的ID.那twitter的snowflake啊就是一个比较好用的全局ID实现。

那最后呢我给出了幂等性接口的处理流程。

在下节课中呢,我们会讲述服务的状态啊,希望能对你有帮助。

也欢迎你分享一下你的分布式服务中所有的交易接口是否都实现了密能性能。

你所使用的全球ID算法又是什么呢?我在文末呢给出了分布式系统设计模式系列文章的目录啊,希望你能在这个列表里找到自己感兴趣的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值