美文网首页
ZK实现分布式锁的正确姿势

ZK实现分布式锁的正确姿势

作者: 大黑跟小白的日常 | 来源:发表于2020-07-19 19:06 被阅读0次

题外话

基于数据库实现分布式锁(性能较低,并发不高的情况下可以使用)

搞一张表——lock(id,value,timeout_stamp),用id主键来互斥;
插入数据成功即加锁成功,将数据删除即解锁;

非阻塞式

image.png

阻塞式

mysql支持的客户端连接,峰值(300-700)

image.png
这里的sleep(10)会导致并发加锁操作的业务性能问题(解锁无通知),如果睡眠时间过短或while(true)会导致数据库访问性能问题;
无法优雅的实现阻塞式加锁
image.png

解锁

image.png

存在的问题

1、lock的id固定写死不合理;
应用不同的id来代表不同的竞争资源;
2、未考虑死锁问题,某客户端加锁成功,操作共享资源,还没有来得及释放锁,客户端宕机,当前id对应的全局lock无法释放;
应该用timeout_stamp字段记录当前锁超时的时间戳,每个客户端在尝试获取锁之前,应该先删除超时的锁
2、谁加的锁应该由谁来释放,避免锁超时导致的线程安全问题,可以用value存UUID,解锁(delete)时用条件判断,不能把别人刚刚加的锁;
主要是考虑到某个客户端(A)在机端情况下,没有在设定的超时时间内完成数据操作,其他客户端已经以超时结果认定并删除锁,这时A完成操作,将其他客户端刚刚创建的锁给删除了,所以解锁delete操作需要判断value值,谁加的锁谁来解除(仅是解锁时判断)。

仍然存在的问题

未考虑锁续命的问题,其他客户端可能会由于超时设定误删正常客户端正在使用的锁,导致线程安全问题。
解决思路分析:压力测试,覆盖性测试,选择最大完成时间+1作为当前id对应资源的锁的超时时间;日志补偿,告警,人为干预;

ZK实现分布式锁的正确姿势

原理分析

1、在对应的lock节点下创建临时顺序节点;
临时节点,在zk客户端宕机,zk会自动检测,移除节点;
2、获取lock下的所有子节点,如果发现自己的是最小的,则认为当前客户端获取到了锁。并且在使用完锁后,需要删除自己创建的临时顺序节点(不能删除别人的);
3、如果发现自己不是最小的,说明自己没有获取锁,此时客户端需要找到比自己小1号的那个节点,同时对其注册事件监听器,监听删除事件;

image.png
如上实现的是公平锁。

图解

image.png

开胃菜

zk监听节点变动,代码演示

image.png

Thread.currentThread().join();不让@Test单元测试线程退出;

正确的使用zk分布式锁的姿势

原生用法

image.png
image.png
image.png
image.png
image.png

见:https://blog.csdn.net/qq_31142553/article/details/85463399

Curator封装较好,基于它来实现

image.png

使用场景

可以用来解决缓存击穿的问题

相关文章

网友评论

      本文标题:ZK实现分布式锁的正确姿势

      本文链接:https://www.haomeiwen.com/subject/kttpzhtx.html