接口幂等性、分布式锁

女神Asuna镇楼!!
前端

 

在分布式系统中,如何优雅地使用分布式锁?mysql

开始咱们的思惟三部曲,what,why,howredis

首先,what,什么是分布式锁?
咱们常说的锁,通常指的是给资源加锁,向外界代表资源正在被某个线程占用,其它企图得到这个资源的线程检测到目标资源被锁住了,就会轮询等待直到锁被占有者释放,或者等待必定时间后放弃资源去作其它事情。算法

至于分布式锁,是特定于分布式环境的,多台机器上的线程都企图得到同一个资源,这时单机环境的锁机制就再也不适用,必须用一个外部独立的第三方管理者协调多台机器上的线程对资源的抢占访问。咱们通常选用redis或zookeeper来担当这个“第三方管理者”。sql

而后,why,为何要使用分布式锁?网络

 

最后,how,怎么使用分布式锁?负载均衡

 

一个分布式系统中的某个接口,该如何保证幂等性?分布式

假如你有个服务提供一些接口供外部调用,这个服务部署在了 5 台机器上,其中有个接口就是付款接口。而后用户在前端上操做的时候,不知道胡乱操做了什么,意外地针对一个订单发起了两次支付请求,而后这两次请求分散在了这个服务部署的不一样的机器上,结果一个订单扣款扣了两次。spa

或者是订单系统调用支付系统进行支付,意外地由于网络超时了,订单系统走了重试机制,致使支付系统收到一个支付请求两次,并且由于负载均衡算法落在了不一样的机器上,结果同样是重复扣款。线程

虽然上面说的都是几率很小的意外事件,可是只要出现了,就会带来很坏的负面影响,客户会愤怒地投诉。

实际上这样的场景并非技术问题,也没有通用的方法,咱们应该结合具体的业务来保证幂等性。

所谓幂等性,就是一个接口,屡次发起同一个请求,接口得保证结果是准确的,好比不能多扣款、不能多插入一条数据、不能将统计值多加了 1。换句话说,请求一次和请求一万次的产生的做用同样,这就是幂等性。

其实保证幂等性主要是三点:

  • 对于每一个请求必须有一个惟一的标识,举个栗子:订单支付请求,确定得包含订单 id,一个订单 id 最多支付一次。
  • 每次处理完请求以后,必须有一个记录标识这个请求处理过了。常见的方案是在 mysql 中用一个字段来记录状态,好比支付以前记录一条这个订单的支付流水。
  • 每次接收请求须要进行判断,判断以前是否处理过。好比说,若是有一个订单已经支付了,就已经有了一条支付流水,若是重复发送这个请求,则此时先插入支付流水,orderId 已经存在了,惟一键约束生效致使报错失败,就不会再继续执行扣款代码了。

实际运做过程当中,你要结合本身的业务来,好比说利用 redis,用 orderId 做为惟一键。只有成功插入这个支付流水,才能够执行实际的支付扣款。

具体的实现逻辑:在支付一个订单以前,先插入一条支付流水,set order_id unpay,在支付完成后,set order_id payed。其中, order_id 是惟一索引 key ,unpay / payed 是对应的 value(标识是否已经支付完成),当下一个重复的请求过来了,先根据key order_id 查询对应的 value,若是是 payed 就说明已经支付过了,直接返回支付成功的记录,若是是unpay,正常调用支付接口进行支付。

相关文章
相关标签/搜索