1.引入业务场景

业务场景一

因为小T刚接手项目,正在吭哧吭哧对熟悉着代码、部署架构。在看代码过程中发现,下单这块代码可能会出现问题,这可是分布式部署的,如果多个用户同时购买同一个商品,就可能导致商品出现 库存超卖 (数据不一致) 现象,对于这种情况代码中并没有做任何控制。

原来一问才知道,以前他们都是售卖的虚拟商品,没啥库存一说,所以当时没有考虑那么多…

这次不一样啊,这次是售卖的实体商品,那就有库存这么一说了,起码要保证不能超过库存设定的数量吧。

小T大眼对着屏幕,屏住呼吸,还好提前发现了这个问题,赶紧想办法修复,不赚钱还赔钱,老板不得疯了,还想不想干了~

业务场景二

小T下面的一位兄弟正在压测,发现个小问题,因为在终端设备上跟鹅厂有紧密合作,调用他们的接口时需要获取到access_token,但是这个access_token过期时间是2小时,过期后需要重新获取。

压测时发现当到达过期时间时,日志看刷出来好几个不一样的access_token,因为这个服务也是分布式部署的,多个节点同时发起了第三方接口请求导致。

虽然以最后一次获取的access_token为准,也没什么不良副作用,但是会导致多次不必要的对第三方接口的调用,也会短时间内造成access_token的 重复无效获取(重复工作)。

以上便于大家理解为什么要用分布式锁才能解决,勾勒出的几个业务场景。上面的问题无一例外,都是针对共享资源要求串行化处理,才能保证安全且合理的操作。

用一张图来体验一下:
分布式锁专题-分布式锁入门_公平锁
此时,使用Java提供的​​​Synchronized​​​、​​ReentrantLock​​​、​​ReentrantReadWriteLock​​…,仅能在单个JVM进程内对多线程对共享资源保证线程安全,在分布式系统环境下统统都不好使,心情是不是拔凉呀。这个问题得请教 分布式锁 家族来支持一下,听说他们家族内有很多成员,每个成员都有这个分布式锁功能,接下来就开始探索一下。

2.分布式锁概述

2.1.为什么需要分布式锁才能解决?

听听 Martin 大佬们给出的说法,请你自己看 Maritin 博客文章:

​https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html​

Martin kleppmann 是英国剑桥大学的分布式系统的研究员,曾经跟 Redis 之父 Antirez 进行过关于 RedLock (Redis里分布式锁的实现算法)是否安全的激烈讨论。

2.2.分布式锁考虑的问题

效率
使用分布式锁可以避免多个客户端重复相同的工作,这些工作会浪费资源。

比如业务场景二,重复获取access_token。

对共享资源的操作是幂等性操作,无论你操作多少次都不会出现不同结果。
本质上就是为了避免对共享资源重复操作,从而提高效率。

正确性:

使用分布式锁同样可以避免锁失效的发生,一旦发生会引起正确性的破坏,可能会导致数据不一致,数据缺失或者其他严重的问题。

2.3.分布式锁特点

以下是分布式锁的一些特点,分布式锁家族成员并不一定都满足这个要求,实现机制不大一样。

互斥性: 分布式锁要保证在多个客户端之间的互斥。
可重入性:同一客户端的相同线程,允许重复多次加锁。
锁超时:和本地锁一样支持锁超时,防止死锁。
非阻塞: 能与 ReentrantLock 一样支持 trylock() 非阻塞方式获得锁。
支持公平锁和非公平锁:公平锁是指按照请求加锁的顺序获得锁,非公平锁真好相反请求加锁是无序的。

3.分布式锁家族实现者介绍

分布式锁家族实现者一览:

分布式锁专题-分布式锁入门_redis_02
下面让他们分别来做下自我介绍:

3.1.数据库实现

排它锁(悲观锁)

基于 select * from table where xx=yy for update SQL语句来实现,有很多缺陷,一般不推荐使用。

乐观锁

表中添加一个时间戳或者版本号的字段来实现,update xx set version = new... where id = y and version = old 当更新不成功,客户端重试,重新读取最新的版本号或时间戳,再次尝试更新,类似 CAS 机制,推荐使用。

3.2.Redis实现

特点:CAP模型属于AP | 无一致性算法 | 性能好

开发常用,如果你的项目中正好使用了redis,不想引入额外的分布式锁组件,推荐使用。

业界也提供了多个现成好用的框架予以支持分布式锁,比如Redisson、spring-integration-redis、redis自带的setnx命令,推荐直接使用。

另外,可基于redis命令和redis lua支持的原子特性,自行实现分布式锁。

3.3.Zookeeper

特点:CAP模型属于CP | ZAB一致性算法实现 | 稳定性好

开发常用,如果你的项目中正好使用了zk集群,推荐使用。

业界有Apache Curator框架提供了现成的分布式锁功能,现成的,推荐直接使用。

另外,可基于Zookeeper自身的特性和原生Zookeeper API自行实现分布式锁。

3.4.其他

Chubby,Google开发的粗粒度分布锁的服务,但是并没有开源,开放出了论文和一些相关文档可以进一步了解,出门百度一下获取文档。

Tair,是阿里开源的一个分布式KV存储方案。

Etcd,CAP模型中属于CP,Raft一致性算法实现。

Hazelcast,是基于内存的数据网格开源项目,提供弹性可扩展的分布式内存计算,并且被公认是提高应用程序性能和扩展性最好的方案,听上去很牛逼。

当然了,上面推荐的常用分布式锁Zookeeper和Redis,使用时还需要根据具体的业务场景,做下权衡,实现功能上都能达到你要的效果,原理上有很大的不同。