分布式系统学习:11 弹力设计篇:幂等性设计

关键词总结:幂等性设计、全局 ID、HTTP 的幂等性

幂等性设计

所谓幂等性设计,就是说,一次和多次请求某一个资源应该具有同样的副作用。(副作用相同而不是结果)
用数学的语言来表达就是:f(x) = f(f(x))。

为什么需要幂等性设计

系统解耦隔离后,服务间的调用可能会有三个状态,一个是成功(Success),一个是失败(Failed),一个是超时(Timeout)。成功与失败是明确的状态,而超时请求方则是完全不知道是什么状态。如果不是幂等的,当请求方再次调用,就会给系统带来不一致的副作用。

例子:

  • 订单创建接口,第一次调用超时了,然后调用方重试了一次。是否会多创建一笔订单?
  • 订单创建时,我们需要去扣减库存,这时接口发生了超时,调用方重试了一次。是否会多扣一次库存?

两种处理方式

  1. 上游系统负责明确状态
    下游系统提供相应的查询接口。上游系统在 timeout 后去查询一下。如果查到了,就表明已经做了,成功了就不用做了,失败了就走失败流程。
  2. 下游系统保证状态实现幂等性
    通过幂等性的方式。也就是说,把这个查询操作交给下游系统,上游系统只管重试,下游系统保证一次和多次的请求结果是一样的。

第一种方式,需要对方提供一个查询接口来做配合。而第二种方式则需要下游的系统提供支持幂等性的交易接口。

全局 ID

要做到幂等性的交易接口,需要有一个唯一的标识,来标志交易是同一笔交易。而这个交易 ID 由谁来分配是一件比较头疼的事。因为这个标识要能做到全局唯一。

  • 中心系统来分配:每次交易需要那个中心系统支持,增加了程序的性能开销
  • 上游系统来分配:上游系统可能会是一个集群,同时承担相同的工作,可能会出现 ID 分配重复的问题。

如何解决ID分配冲突的问题

为了解决分配冲突的问题,需要使用一个不会冲突的算法。

可以借助由 Twitter 开源的基于全局唯一 ID 算法实现的分布式 ID 生成算法项目 Snowflake。其核心思想是,产生一个 long 型的 ID

  • 前 41 位:毫秒数,需要 69.7 年到达上线。
  • 中 10 位:机器编号(前 5 位是数据中心,后 5 位是机器编号),支持 1024 个实例。
  • 后 12 位:毫秒内序列号。每毫秒 4096 个序号。

幂等性的处理流程

对于幂等性的处理流程,就是要过滤一下已经收到的交易。当收到交易请求的时候,查询来记录收到的交易的存储,如果查找到了,那么就不再做查询了,并把上次做的结果返回。如果没有查到,那么我们就记录下来。

图片来自极客时间左耳听风专栏

绝大多数请求应该都不会是重新发送,如果每次请求都去存储里去查一下,这会导致处理流程变得很慢。

这时如果这个存储出现冲突的时候会自己报错就最好了。也就是,收到交易请求 -> 去存储里记录这个 ID(相对于数据的 Insert 操作) -> 如果出现 ID 冲突了的异常,表示之前已经有人发过来了,就不用再做了。

HTTP 的幂等性

GET

  • 幂等:是
  • 副作用: 无
  • 用途:用于获取资源
  • GET不会改变资源的状态,不论调用一次还是 N 次都没有副作用。(副作用相同不是结果相同)

HEAD

  • 幂等:是
  • 副作用: 无
  • 用途:用于获取头信息
  • 获取接口返回的 Header 数据,每次调用的结果都相同。

OPTIONS

  • 幂等:是
  • 副作用: 无
  • 用途:用于获取当前 URL 所支持的方法
  • 获取接口所支持的 HTTP 方法,每次调用的结果都相同。

DELETE

  • 幂等:是
  • 副作用: 有
  • 用途:用于删除资源
  • 调用一次和 N 次对系统产生的副作用是相同的,即删掉某个资源

POST

  • 幂等:否
  • 副作用: 有
  • 用途:用于创建资源,对应的 URI 并** 非创建的资源本身**,而是去执行创建动作的操作者
  • 两次相同的 POST 请求会在服务器端创建两份资源

PUT

  • 幂等:是
  • 副作用: 有
  • 用途:用于创建或更新操作,所对应的 URI 是要创建或更新的资源本身
  • 对同一 URI 进行多次 PUT 的副作用和一次 PUT 是相同的

POST的幂等性设计

对于 POST 的方式,很可能会出现多次提交的问题,比如我们在论坛中发贴时,有时候因为网络有问题,可能会对同一篇贴子出现多次提交的情况。

  • 首先,在表单中需要隐藏一个 token(表单的唯一标识)。(这种情况其实是通过前端生成 ID 把 POST 变成了 PUT。)
  • 然后,当用户点击提交后,后端把数据和这个 token 保存在数据库中。如果有重复提交,那么数据库中的 token 会做排它限制,从而做到幂等性。
  • 更为稳妥的做法是,后端成功后向前端返回 302 跳转,把用户的前端页跳转到 GET 请求,把刚刚 POST 的数据给展示出来,如果是 Web 上的最好还把之前的表单设置成过期。PRG 模式(Post/Redirect/Get)

参考资料:

左耳听风(极客时间)链接:
http://gk.link/a/10f5D


GitHub链接:
https://github.com/lichangke/LeetCode
CSDN首页:
https://me.csdn.net/leacock1991
欢迎大家来一起交流学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

墨1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值