@@ -12,7 +12,7 @@ icon: "lock"
12
12
13
13
下面是我对本地锁画的一张示意图。
14
14
15
- ![ 本地锁] ( ./images /distributed-lock/jvm-local-lock.png)
15
+ ![ 本地锁] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/jvm-local-lock.png)
16
16
17
17
从图中可以看出,这些线程访问共享资源是互斥的,同一时刻只有一个线程可以获取到本地锁访问共享资源。
18
18
@@ -22,7 +22,7 @@ icon: "lock"
22
22
23
23
下面是我对分布式锁画的一张示意图。
24
24
25
- ![ 分布式锁] ( ./images /distributed-lock/distributed-lock.png)
25
+ ![ 分布式锁] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/distributed-lock.png)
26
26
27
27
从图中可以看出,这些独立的进程中的线程访问共享资源是互斥的,同一时刻只有一个线程可以获取到分布式锁访问共享资源。
28
28
69
69
end
70
70
```
71
71
72
- ![ Redis 实现简易分布式锁] ( ./images /distributed-lock/distributed-lock-setnx.png)
72
+ ![ Redis 实现简易分布式锁] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/distributed-lock-setnx.png)
73
73
74
74
这是一种最简易的 Redis 分布式锁实现,实现方式比较简单,性能也很高效。不过,这种方式实现分布式锁存在一些问题。就比如应用程序遇到一些问题比如释放锁的逻辑突然挂掉,可能会导致锁无法被释放,进而造成共享资源无法再被其他线程/进程访问。
75
75
@@ -103,7 +103,7 @@ Redisson 是一个开源的 Java 语言 Redis 客户端,提供了很多开箱
103
103
104
104
Redisson 中的分布式锁自带自动续期机制,使用起来非常简单,原理也比较简单,其提供了一个专门用来监控和续期锁的 ** Watch Dog( 看门狗)** ,如果操作共享资源的线程还未执行完成的话,Watch Dog 会不断地延长锁的过期时间,进而保证锁不会因为超时而被释放。
105
105
106
- ![ Redisson 看门狗自动续期] ( ./images /distributed-lock/distributed-lock-redisson-renew-expiration.png)
106
+ ![ Redisson 看门狗自动续期] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/distributed-lock-redisson-renew-expiration.png)
107
107
108
108
看门狗名字的由来于 ` getLockWatchdogTimeout() ` 方法,这个方法返回的是看门狗给锁续期的过期时间,默认为 30 秒([ redisson-3.17.6] ( https://github.com/redisson/redisson/releases/tag/redisson-3.17.6 ) )。
109
109
@@ -207,19 +207,19 @@ lock.lock(10, TimeUnit.SECONDS);
207
207
208
208
实际项目中,我们不需要自己手动实现,推荐使用我们上面提到的 ** Redisson** ,其内置了多种类型的锁比如可重入锁(Reentrant Lock)、自旋锁(Spin Lock)、公平锁(Fair Lock)、多重锁(MultiLock)、 红锁(RedLock)、 读写锁(ReadWriteLock)。
209
209
210
- ![ ] ( ./images /distributed-lock/redisson-readme-locks.png)
210
+ ![ ] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/redisson-readme-locks.png)
211
211
212
212
### Redis 如何解决集群情况下分布式锁的可靠性?
213
213
214
214
为了避免单点故障,生产环境下的 Redis 服务通常是集群化部署的。
215
215
216
216
Redis 集群下,上面介绍到的分布式锁的实现会存在一些问题。由于 Redis 集群数据同步到各个节点时是异步的,如果在 Redis 主节点获取到锁后,在没有同步到其他节点时,Redis 主节点宕机了,此时新的 Redis 主节点依然可以获取锁,所以多个应用服务就可以同时获取到锁。
217
217
218
- ![ ] ( ./images /distributed-lock/redis-master-slave-distributed-lock.png)
218
+ ![ ] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/redis-master-slave-distributed-lock.png)
219
219
220
220
针对这个问题,Redis 之父 antirez 设计了 [ Redlock 算法] ( https://redis.io/topics/distlock ) 来解决。
221
221
222
- ![ ] ( ./images /distributed-lock/distributed-lock-redis.io-realock.png)
222
+ ![ ] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/distributed-lock-redis.io-realock.png)
223
223
224
224
Redlock 算法的思想是让客户端向 Redis 集群中的多个独立的 Redis 实例依次请求申请加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,那么我们就认为,客户端成功地获得分布式锁,否则加锁失败。
225
225
@@ -254,7 +254,7 @@ ZooKeeper 分布式锁是基于 **临时顺序节点** 和 **Watcher(事件监
254
254
2 . 成功获取锁的客户端在出现故障之后,对应的子节点由于是临时顺序节点,也会被自动删除,避免了锁无法被释放。
255
255
3 . 我们前面说的事件监听器其实监听的就是这个子节点删除事件,子节点删除就意味着锁被释放。
256
256
257
- ![ ] ( ./images /distributed-lock/distributed-lock-zookeeper.png)
257
+ ![ ] ( https://oss.javaguide.cn/github/javaguide/distributed-system /distributed-lock/distributed-lock-zookeeper.png)
258
258
259
259
实际项目中,推荐使用 Curator 来实现 ZooKeeper 分布式锁。Curator 是 Netflix 公司开源的一套 ZooKeeper Java 客户端框架,相比于 ZooKeeper 自带的客户端 zookeeper 来说,Curator 的封装更加完善,各种 API 都可以比较方便地使用。
260
260
0 commit comments