Zookeeper实战-分布式锁
1. 简介
我们在之前的博文中讲解了如何使用redis实现分布式锁,其实除了 redis 还有 zookeeper 也能实现分布式锁。
废话不多说,直接上图。
从整个流程中可以看出,zk实现分布式锁,主要是靠zk的临时顺序节点和watch机制实现的。
2. quick start
Curator 是 Netflix 公司开源的一套 zookeeper 客户端框架,解决了很多 Zookeeper 客户端非常底层的细节开发工作,包括连接重连、反复注册 Watcher 和 NodeExistsException 异常等。
curator-recipes:封装了一些高级特性,如:Cache 事件监听、选举、分布式锁、分布式计数器、分布式 Barrier 等。
2.1 引入依赖
curator-recipes
中已经依赖了zookeeper
和curator-framework
jar,所以这里不用额外的依赖其他jar。
2.2 测试代码
测试代码其实很简单,只需要几行代码而已,初始化客户端,创建锁对象,加锁 和 释放锁。
这里先把加锁的代码注释掉,试下不加锁的情况。
2.3 启动测试
这里我们使用jemter进行模拟并发请求,当然我们这里只启动了一个server,主要是为了节约文章篇幅(启动多个server还得连接db...),能说明问题即可。
同一时刻发送一百个请求。
测试结果部分日志如下:
很明显出现了超卖了现象,并且请求是无序的(请求是非公平的)。
此时我们将注释的加锁代码打开,再进行测试。
测试结果部分日志如下:
很明显没有出现超卖的现象。
通过zk 客户端工具查看创建的部分临时节点如下:
3. 源码解析
3.1 加锁逻辑
我们再通过查看Curator加锁源码来验证下我们的加锁逻辑。
首先我们查看InterProcessMutex::acquire()
方法,并且我们通过注释可以得知该方法加的锁是可重入锁。
查看internalLock
方法如下。
我们继续查看LockInternals::attemptLock()
尝试获取锁逻辑如下。
在这里先查看下创建锁的逻辑StandardLockInternalsDriver::createsTheLock()
,如下。
锁创建成功后我们再查看下程序是如何加锁的LockInternals::internalLockLoop()
。
最后 我们再看下上段代码中提到的很关键的方法driver.getsTheLock() 即 StandardLockInternalsDriver::getsTheLock()
。
3.2 小节
其实加锁的源码还是比较清晰和易懂的,我们在这里再总结下。
- 执行
InterProcessMutex::acquire()
加锁方法。 InterProcessMutex::internalLock()
判断当前线程是加过锁,如果加过则加锁次数+1实现锁的重入,如果没有加过锁,则调用LockInternals::attemptLock()
尝试获取锁。LockInternals::attemptLock()
首先创建Container
父节点再创建临时的顺序节点,然后执行加锁方法LockInternals::internalLockLoop()
。LockInternals::internalLockLoop()
- 先获取当前
Container
下的所有顺序子节点并且按照从小到大排序。 - 调用
StandardLockInternalsDriver::getsTheLock()
方法加锁,先判断当前节点是不是最小的顺序节点,如果是则加锁成功,如果不是则返回上一个比他小的节点,作为被监听的节点。 - 上一步加锁成功则返回true,如果失败则执行监听逻辑。
- 先获取当前
3.3 释放锁逻辑
4. redis 和 zookeeper
Zookeeper采用临时节点和事件监听机制可以实现分布式锁,Redis主要是通过setnx命令实现分布式锁。
Redis需要不断的去尝试获取锁,比较消耗性能,Zookeeper是可以通过对锁的监听,自动获取到锁,所以性能开销较小。
另外如果获取锁的jvm出现bug或者挂了,那么只能redis过期删除key或者超时删除key,Zookeeper则不存在这种情况,连接断开节点则会自动删除,这样会即时释放锁。
这样一听感觉zk的优势还是很大的。
但是要考虑一个情况在锁并发不高的情况下 zk没有问题 如果在并发很高的情况下 zk的数据同步 可能造成锁时延较长,在选举过程中需要接受一段时间zk不可用(因为ZK 是 CP 而 redis集群是AP)。
所以说没有哪个技术是适用于任何场景的,具体用哪个技术,还是要结合当前的技术架构和业务场景做选型和取舍。
__EOF__

本文链接:https://www.cnblogs.com/ludangxin/p/15236163.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示