
分布式锁,式锁顾名思义,现原就是分布在分布式环境下使用的锁 。众所周知,式锁在并发编程中,现原我们经常需要借助并发控制工具,分布如 mutex 、式锁synchronized 等 ,现原来保障线程安全。分布但是式锁,这种线程安全仅作用在同一内存环境中。现原在实际业务中 ,分布为了保障服务的云计算式锁可靠性,我们通常会采用多节点进行部署。现原在这种分布式情况下,各实例间的内存不共享 ,线程安全并不能保证并发安全,如下例,同一实例中线程A与线程B之间的并发安全并不能保证实例1与实例2之间的并发安全:

因此 ,当遇到分布式系统的并发安全问题时,我们就可能会需要引入分布式锁来解决。
用于实现分布式锁的组件通常都会具备以下的一些特性:
互斥性 :提供分布式环境下的亿华云互斥原语来加锁/释放锁 ,当然是分布式锁最基本的特性 。 自动释放:为了应对分布式系统中各实例因通信故障导致锁不能释放的问题,自动释放的特性通常也是很有必要的 。分区容错性:应用在分布式系统的组件,具备分区容错性也是一项重要的特性 ,否则就会成为整个系统的服务器租用瓶颈。目前开源社区中常见的分布式锁解决方案,大多是基于具备集群部署能力的 key-value 存储中间件来实现 ,最为常用的方案基本上是基于 Redis 、zookeeper 来实现 ,笔者将从上述分布式锁的特性出发,介绍一下这两类的分布式锁解决方案的优缺点。
Redis 由于其高性能、使用及部署便利性 ,在很多场景下是实现分布式锁的首选 。首先我们看下 Redis 是如何实现互斥性的 。在单机部署的模式下,Redis 由于其单线程处理命令的线程模型,天然的具备互斥能力;而在哨兵/集群模式下,写命令也是建站模板单独发送到某个单独节点上进行处理,可以保证互斥性;其核心的命令是 set [NX](set if ot exist):
复制SET lockKey lockValue NX1.成功设置 lockValue 的实例 ,就相当于抢锁成功 。但如果持有锁的实例宕机,因为 Redis 服务端并没有感知客户端状态的能力,因此会出现锁无法释放的问题:

这种情况下,就需要给 key 设置一个过期时间 expireTime :
复制SET lockKey lockValue EX expireTime NX1.左右滑动查看完整代码
如果持有锁的实例宕机无法释放锁 ,则锁会自动过期 ,这样可以就避免锁无法释放的源码库问题 。在一些简单的场景下 ,通过该方式实现的分布式锁已经可以满足需求。但这种方式存在一个明显问题:如果业务的实际处理时间比锁过期时间长,锁就会被误释放,导致其他实例也可以加锁:

这种情况下,就需要通过其他机制来保证锁在业务处理结束后再释放,一个常用的方式就是通过后台线程的方式来实现锁的自动续期 。

Redssion 是开源社区中比较受欢迎的一个 Java 语言实现的 Redis 客户端 ,其对 Java 中 Lock 接口定义进行扩展 ,实现了 Redis 分布式锁 ,并通过 watchDog 机制(本质上即是后台线程运作)来对锁进行自动续期 。以下是一个简单的 Reddison 分布式锁的使用例子 :
复制RLock rLock = RedissonClient.getLock("test-lock"); try { if (rLock.tryLock()) { // do something } } finally { rLock.unlock(); }1.2.3.4.5.6.7.8.左右滑动查看完整代码
Redssion 的默认实现 RedissonLock 为可重入互斥非公平锁,其 tryLock 方法会基于三个可选参数执行 :
waitTime(获取锁的最长等待时长)