常州金坛建设局网站装修计算器在线计算
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:10
当前位置: 首页 > news >正文
常州金坛建设局网站,装修计算器在线计算,搭建小程序要钱吗,163网易企业邮箱注册分布式锁的概念
分布式锁其实可以理解为#xff1a;控制分布式系统有序的去对共享资源进行操作#xff0c;通过互斥来保持一致性。
举个例子#xff1a;假设共享的资源就是一个房子#xff0c;里面有各种书#xff0c;分布式系统就是要进屋看书的人#xff0c; 分布式锁…分布式锁的概念
分布式锁其实可以理解为控制分布式系统有序的去对共享资源进行操作通过互斥来保持一致性。
举个例子假设共享的资源就是一个房子里面有各种书分布式系统就是要进屋看书的人 分布式锁就是保证这个房子只有一个门并且一次只有一个人可以进而且门只有一把钥匙。 然后许多人要去看书可以排队第一个人拿着钥匙把门打开进屋看书并且把门锁上 然后第二个人没有钥匙那就等着等第一个出来然后你在拿着钥匙进去然后就是以此类推。
锁存在的意义
原因其实很简单因为我们想让同一时刻只有一个线程在执行某段代码。
因为如果同时出现多个线程去执行可能会带来我们不想要的结果可能是数据错误也可能是服务宕机等等。
以淘宝双11为例在0点这一刻如果有几十万甚至上百万的人同时去查看某个商品的详情这时候会触发商品的查询如果我们不做控制全部走到数据库去那是有可能直接将数据库打垮的。
这个时候一个比较常用的做法就是进行加锁只让1个线程去查询其他线程待等待这个线程的查询结果后直接拿结果。在这个例子中锁用于控制访问数据库的流量最终起到了保护系统的作用。
再举个例子某平台做活动“秒杀茅台”假如活动只秒杀1瓶但是同时有10万人在同一时刻去抢如果底层不做控制有10000个人抢到了额外的9999瓶平台就要自己想办法解决了。此时我们可以在底层通过加锁或者隐式加锁的方式来解决这个问题。
此外锁也经常用来解决并发下的数据安全方面的问题这里就不一一举例了。
分布式锁存在的意义
分布式锁是锁的一种通常用来跟 JVM 锁做区别。
JVM 锁就是我们常说的 synchronized、Lock。
JVM 锁只能作用于单个 JVM可以简单理解为就是单台服务器容器而对于多台服务器之间JVM 锁则没法解决这时候就需要引入分布式锁。
实现分布式锁的方式
实现分布式锁的方式其实很多只要能保证对于抢夺“锁”的系统来说这个东西是唯一的那么就能用于实现分布式锁。
举个简单的例子有一个 MySQL 数据库 OrderOrder 库里有个 Lock 表只有一条记录该记录有个状态字段 lock_status默认为0表示空闲状态可以修改为1表示成功获取锁。
我们的订单系统部署在100台服务器上这100台服务器可以在“同一时刻”对上述的这1条记录执行修改修改内容都是从0修改为1但是 MysQL 会保证最终只会有1个线程修改成功。因此这条记录其实就可以用于做分布式锁。
常见实现分布式锁的方式有数据库、Redis、Zookeeper。
这其中又以 Redis 最为常见。
Redis 实现分布式锁
加锁
加锁通常使用 set 命令来实现伪代码如下
set key value PX milliseconds NX几个参数的意义如下
key、value键值对PX milliseconds设置键的过期时间为 milliseconds 毫秒。NX只在键不存在时才对键进行设置操作。SET key value NX 效果等同于 SETNX key value。PX、expireTime 参数则是用于解决没有解锁导致的死锁问题。因为如果没有过期时间万一程序员写的代码有 bug 导致没有解锁操作则就出现了死锁因此该参数起到了一个“兜底”的作用。NX 参数用于保证在多个线程并发 set 下只会有1个线程成功起到了锁的“唯一”性。
解锁
解锁需要两步操作
1查询当前“锁”是否还是我们持有因为存在过期时间所以可能等你想解锁的时候“锁”已经到期然后被其他线程获取了所以我们在解锁前需要先判断自己是否还持有“锁”
2如果“锁”还是我们持有则执行解锁操作也就是删除该键值对并返回成功否则直接返回失败。
由于当前 Redis 还没有原子命令直接支持这两步操作所以当前通常是使用 Lua 脚本来执行解锁操作Redis 会保证脚本里的内容执行是一个原子操作。
脚本代码如下逻辑比较简单
if redis.call(get,KEYS[1]) ARGV[1]
thenreturn redis.call(del,KEYS[1])
elsereturn 0
end两个参数的意义如下 KEYS[1]我们要解锁的 key ARGV[1]我们加锁时的 value用于判断当“锁”是否还是我们持有如果被其他线程持有了value 就会发生变化。
Redis 分布式锁过期了还没处理完怎么办
为了防止死锁我们会给分布式锁加一个过期时间但是万一这个时间到了我们业务逻辑还没处理完怎么办
首先我们在设置过期时间时要结合业务场景去考虑尽量设置一个比较合理的值就是理论上正常处理的话在这个过期时间内是一定能处理完毕的。
之后我们再来考虑对这个问题进行兜底设计。
关于这个问题目前常见的解决方法有两种
1、守护线程“续命”额外起一个线程定期检查线程是否还持有锁如果有则延长过期时间。Redisson 里面就实现了这个方案使用“看门狗”定期检查每1/3的锁时间检查1次如果线程还持有锁则刷新过期时间。
2、超时回滚当我们解锁时发现锁已经被其他线程获取了说明此时我们执行的操作已经是“不安全”的了此时需要进行回滚并返回失败。
同时需要进行告警人为介入验证数据的正确性然后找出超时原因是否需要对超时时间进行优化等等。
守护线程续命的方案有什么问题吗
Redisson 使用看门狗守护线程“续命”的方案在大多数场景下是挺不错的也被广泛应用于生产环境但是在极端情况下还是会存在问题。
问题例子如下
1、线程1首先获取锁成功将键值对写入 redis 的 master 节点
2、在 redis 将该键值对同步到 slave 节点之前master 发生了故障
3、redis 触发故障转移其中一个 slave 升级为新的 master
4、此时新的 master 并不包含线程1写入的键值对因此线程2尝试获取锁也可以成功拿到锁
5、此时相当于有两个线程获取到了锁可能会导致各种预期之外的情况发生例如最常见的脏数据
解决方法上述问题的根本原因主要是由于 redis 异步复制带来的数据不一致问题导致的因此解决的方向就是保证数据的一致。
当前比较主流的解法和思路有两种
1Redis 作者提出的 RedLock
2Zookeeper 实现的分布式锁。
接下来介绍下这两种方案。
RedLock
首先该方案也是基于文章开头的那个方案set加锁、lua脚本解锁进行改良的所以 antirez 只描述了差异的地方大致方案如下。
假设我们有 N 个 Redis 主节点例如 N 5这些节点是完全独立的我们不使用复制或任何其他隐式协调系统为了取到锁客户端应该执行以下操作:
1、获取当前时间以毫秒为单位。
2、依次尝试从5个实例使用相同的 key 和随机值例如UUID获取锁。当向Redis 请求获取锁时客户端应该设置一个超时时间这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为10秒则超时时间应该在 5-50 毫秒之间。这样可以防止客户端在试图与一个宕机的 Redis 节点对话时长时间处于阻塞状态。如果一个实例不可用客户端应该尽快尝试去另外一个Redis实例请求获取锁。
3、客户端通过当前时间减去步骤1记录的时间来计算获取锁使用的时间。当且仅当从大多数N/21这里是3个节点的Redis节点都取到锁并且获取锁使用的时间小于锁失效时间时锁才算获取成功。
4、如果取到了锁其有效时间等于有效时间减去获取锁所使用的时间步骤3计算的结果。
5、如果由于某些原因未能获得锁无法在至少N/21个Redis实例获取锁、或获取锁的时间超过了有效时间客户端应该在所有的Redis实例上进行解锁即便某些Redis实例根本就没有加锁成功防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁。
可以看出该方案为了解决数据不一致的问题直接舍弃了异步复制只使用 master 节点同时由于舍弃了 slave为了保证可用性引入了 N 个节点官方建议是 5。
该方案看着挺美好的但是实际上我所了解到的在实际生产上应用的不多主要有两个原因1该方案的成本似乎有点高需要使用5个实例2该方案一样存在问题。
该方案主要存以下问题
1严重依赖系统时钟。如果线程1从3个实例获取到了锁但是这3个实例中的某个实例的系统时间走的稍微快一点则它持有的锁会提前过期被释放当他释放后此时又有3个实例是空闲的则线程2也可以获取到锁则可能出现两个线程同时持有锁了。
2如果线程1从3个实例获取到了锁但是万一其中有1台重启了则此时又有3个实例是空闲的则线程2也可以获取到锁此时又出现两个线程同时持有锁了。
针对以上问题其实后续也有人给出一些相应的解法但是整体上来看还是不够完美所以目前实际应用得不是那么多。
Zookeeper 实现分布式锁
Zookeeper 的分布式锁实现方案如下
1、创建一个锁目录 /locks该节点为持久节点
2、想要获取锁的线程都在锁目录下创建一个临时顺序节点
3、获取锁目录下所有子节点对子节点按节点自增序号从小到大排序
4、判断本节点是不是第一个子节点如果是则成功获取锁开始执行业务逻辑操作如果不是则监听自己的上一个节点的删除事件
5、持有锁的线程释放锁只需删除当前节点即可。
6、当自己监听的节点被删除时监听事件触发则回到第3步重新进行判断直到获取到锁。
由于 Zookeeper 保证了数据的强一致性因此不会存在之前 Redis 方案中的问题整体上来看还是比较不错的。
Zookeeper 方案的主要问题在于性能不如 Redis 那么好当申请锁和释放锁的频率较高时会对集群造成压力此时集群的稳定性可用性能可能又会遭受挑战。
分布式锁的选型
当前主流的方案有两种
1Redis 的 set 加锁lua 脚本解锁方案至于是不是用守护线程续命可以结合自己的场景去决定个人建议还是可以使用的。
2Zookeeper 方案
通常情况下对于数据的安全性要求没那么高的可以采用 Redis 的方案对数据安全性要求比较高的可以采用 Zookeeper 的方案。
最后
当你的才华还撑不起你的野心的时候你就应该静下心来学习愿你在我这里能有所收获。
- 上一篇: 常州金坛建设局网站有做h的小说网站
- 下一篇: 常州免费企业网站建设塘厦网站建设公司
相关文章
-
常州金坛建设局网站有做h的小说网站
常州金坛建设局网站有做h的小说网站
- 技术栈
- 2026年03月21日
-
常州建设网站公司app展示网站模板html5
常州建设网站公司app展示网站模板html5
- 技术栈
- 2026年03月21日
-
常州建设企业网站如何建立免费公司网站
常州建设企业网站如何建立免费公司网站
- 技术栈
- 2026年03月21日
-
常州免费企业网站建设塘厦网站建设公司
常州免费企业网站建设塘厦网站建设公司
- 技术栈
- 2026年03月21日
-
常州模板网站建设信息seo的全称是什么
常州模板网站建设信息seo的全称是什么
- 技术栈
- 2026年03月21日
-
常州哪些网站公司做的好处建站过程
常州哪些网站公司做的好处建站过程
- 技术栈
- 2026年03月21日






