1 什么是分布式锁?
分布式锁,即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题,而分布式锁,就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是,分布式系统中竞争共享资源的最小粒度从线程升级成了进程。相对应的是线程锁、进程锁。
线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。
进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronized等线程锁实现进程锁。
分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。
2 分布式锁的实现方式
基于数据库实现分布式锁,基于Zookeeper实现分布式锁,基于reids实现分布式锁
2.1 基于数据库实现分布式锁
使用专用的数据表:
适用场景:没有其他中间件可以使用,需要加锁的资源恰好有对应的数据表
优点:理解起来简单,不需要维护其他中间件
缺点:需要自己实现加锁/解锁过程,性能较差
2.2 基于数据库实现分布式锁基于Zookeeper实现分布式锁
线程去创建/resource_name子节点时会自动编号,第一个编号是/0000001。
第一个线程去创建锁成功并且发现编号是/0000001并且是最小编号,那就直接保留执行程序;
第二个线程再去获取锁时,创建的子节点会自动编号为/0000002,该线程会发现这个节点不是最小节点,就向上一个节点/0000001设置一个watcher监视器,待/0000001线程执行完毕释放的时候就直接触发/0000002执行程序;
第三个个线程再去获取锁时,创建的子节点会自动编号为/0000003,该线程会发现这个节点不是最小节点,就向上一个节点/000000x设置一个watcher监视器,待/000000x线程执行完毕释放的时候就直接触发/0000003执行程序;
解锁流程:
- 进行重入的判断(利用ThreadLocal)
- 若为重入,在重入次数减1,返回
- 删除zookeeper上的有序节点
2.3 基于reids实现分布式锁
redis(remote dictionary server)是一个k-v存储中间件。
关键点:
a. 对key不设置过期时间,由Redisson在加锁成功后给维护一个watchdog看门狗,watchdog负责定时监听并处理,在锁没有被释放且快要过期的时候自动对锁进行续期,保证解锁前锁不会自动失效
b. 通过Lua脚本实现了加锁和解锁的原子操作
c. 通过记录获取锁的客户端id,每次加锁时判断是否是当前客户端已经获得锁,实现了可重入锁。
redis分布式锁实现原理图
加锁后开启一个守护线程进行监听"看门狗"。Redisson超时时间默认设置30s,线程每10s调用一次判断锁还是否存在,如果存在则延长锁的超时时间。
资源:
https://www.cnblogs.com/Mufasa/p/15978320.html
https://blog.csdn.net/qq_42764269/article/details/122412431
标签:加锁,实现,线程,进程,节点,分布式 From: https://www.cnblogs.com/ningshare/p/16916297.html