分布式锁
分布式锁
-
借助数据库、Redis集群、Zookeeper集群作为辅助系统。
-
面临的问题:
-
锁的一致性问题:在集群式辅助系统中,必然会存在锁的并发读,由于集群内部的数据同步存在延迟,不同客户端进程读到的锁可能不一致。
- Zookeeper天生支持最终一致性,能在一定程度上满足。
- Redison借助Redis集群借助redlock机制,也能保证最终一致性。
-
锁得不到释放:持有锁的进程崩溃,导致锁得不到释放,进一步导致其他进程被永久等待,称之为锁得不到释放。
- 解决思路:给锁预设过期时间,一旦超超时锁会被强制释放,解决了永久等待问题。
-
锁的过早释放:新问题又产生了,预设的过期时间往往是一个经验值,可能出现持有锁的进程的正常逻辑还没执行完毕,锁就被错误的强制过期了,这时其他进程将会错误的执行,称之为锁的过早释放。
- 简单粗暴,将超时时间设长一点,比如一分钟,这样能避免大部分的错误强制释放,但如果频繁发生进程故障,将导致大量的无效等待,优点是实现简单,不需要做额外开发,利用Redis的setIfAbsent+expire机制就可以实现。Redison就是基于此,同时在应用中开启后台线程定期给锁续约,避免锁的过早释放。
- 给锁增加监听机制,一旦持有者崩溃就自动释放锁,将锁的释放权完全交给持有进程,这种方式合理高效,但实现复杂。
-
1、数据库实现
进程a先查询表,如果没有记录就向表中插入锁,拿到了锁,继续处理自己的逻辑;
进程b也做同样的操作,查询发现表中已存在记录,表示锁被他人持有,进程b自旋查询等待;
进程a处理完自己的逻辑后删除表中的记录。
进程b查询表发现没有记录,将锁插入表,拿到了锁,继续处理自己的逻辑。
2、Zookeeper实现
每一个进程都到某个znode下创建一个临时有序子节点,同时每个进程都监听这个父znode。
父znode下的每个子节点的变动都会触发进程重新拉取子节点列表,每个进程得到列表后比较自己的节点是否是列表中最小的那一个,如果是则表示得到了锁。执行完毕后断开连接,session失效对应的节点被删除,完成锁的释放。
3、Redison实现
借助setIfAbsent + expire + redlock + 后台续约线程。
学习使我充实,分享给我快乐!