我做的网站怎么是危险网站,没建网站 备案,html5制作手机网站,那个网站做直播好Redis原理篇——分布式锁 分布式锁是什么#xff1f;分布式锁有哪些特性#xff1f;分布式锁常用实现方式Redis 实现分布式锁一、简单的 Redis 锁二、带过期时间的 Redis 锁三、加上 Owner 的 Redis 锁四、Lua 脚本确保原子性 分布式锁是什么#xff1f;
分布式锁是在分布式… Redis原理篇——分布式锁 分布式锁是什么分布式锁有哪些特性分布式锁常用实现方式Redis 实现分布式锁一、简单的 Redis 锁二、带过期时间的 Redis 锁三、加上 Owner 的 Redis 锁四、Lua 脚本确保原子性 分布式锁是什么
分布式锁是在分布式系统中用来确保当多个进程或服务在不同的计算机上同时尝试访问和操作同一份资源时能够协调一致地进行避免数据冲突和不一致性的问题。
分布式锁就像是一个网络版的门卫确保在多台计算机上运行的程序不会同时操作同一个数据。想象一下每台计算机都要先拿到这个门卫的钥匙才能操作数据。这样就能防止数据混乱确保每次只有一个程序在使用数据。 分布式锁有哪些特性
互斥性很好理解确保在任何时刻只有一个客户端可以持有锁。这意味着当一个进程或线程成功获取到锁时其他任何尝试获取该锁的进程或线程都会被阻止直到锁被释放。 老王进去了老李就不能再进了 锁失效机制为了 防止死锁分布式锁应该具有 超时机制 。如果持有锁的进程因崩溃或其他原因未能释放锁锁将在设定的超时时间后自动释放。 老王在里面干太久了这不行挂了都不知道甭管你挂没挂不出来拉倒别人还要进去呐 对称性加锁的必须和解锁的是 同一个竞争者 不能把其他的竞争者持有的锁给释放掉了 跟大爷打招呼拿着钥匙进去的得和出来的时候还钥匙的是一个人不能老王进去老李出来吧那不见鬼了 高可用需要能有一定程度的 异常处理能力 和 容灾能力 确保业务不会出现中断 保安大爷不行了干不动了换那个新来的大学生顶上啊 分布式锁常用实现方式
基于缓存如 Redis使用缓存系统的原子操作来实现锁。例如Redis的SETNX命令可以用来设置一个不存在的键如果键已存在则操作失败这可以用来实现锁的互斥性。基于数据库利用数据库的唯一性约束来实现锁机制。通过向数据库表中插入具有唯一索引的记录来获取锁操作完成后删除记录来释放锁。基于ZookeeperZookeeper提供了一种基于临时节点和顺序节点的锁实现机制。客户端可以创建一个临时顺序节点并检查是否为最小节点来获取锁释放锁时删除该节点。
而本篇文章将基于 Redis 缓存详细探讨分布式锁的使用
Redis 实现分布式锁
一、简单的 Redis 锁
想象一下我们的系统是一个超级忙碌的酒吧而分布式锁就是酒吧里唯一的洗手间的钥匙。客户也就是进程想要使用洗手间也就是资源他们需要先拿到钥匙。
SET restroom_key occupied NX这条命令就像是在问酒保“嘿洗手间钥匙在吗”如果NXNot eXists标志起作用那就意味着洗手间空着你就可以拿到钥匙也就是锁。如果钥匙“不存在”那就意味着洗手间已经有人在用了你得等等。最后在使用完成之后会归还钥匙delete
不足之处
但是如果老王进了洗手间然后突然不见了也就是进程崩溃了或者没卫生纸了需要其他人递过来但又没手机发生死锁怎么办我们的钥匙就永远被锁在里面了。这就引出了我们的第二部分。
二、带过期时间的 Redis 锁
为了防止洗手间被永久占用我们给钥匙加上了一个计时器。
SET restroom_key occupied NX EX 5现在不管老王发生了什么5分钟后钥匙也会自动回到酒保手里其他客户就可以使用洗手间了。
进一步的不足
但是如果老王今天身体确实不舒服窜了太长的时间了或者因为其他原因接个电话什么 比如说网络延迟或者 GC卡顿等原因导致他没消失但一直占着茅坑不拉屎然后钥匙回到了酒保手上另一个人老张就拿着钥匙进去了
然后关键来了这时候老王结束了然后出来的时候按照流程就把钥匙也就是锁但是实际上他还的是老张的钥匙而这时候老张不就完犊子了你老王的问题别把我也扯进去
三、加上 Owner 的 Redis 锁
分布式锁应该满足 谁申请谁释放 的原则不能释放别人的锁
因此我们决定在钥匙锁上刻上名字这样只有名字匹配的人一般是进程的 uuid 才能归还钥匙。
SET restroom_key “老张” NX EX 5
如果老张有了钥匙那么只有老张能归还它。如果老王试图归还一个写着“老张”的钥匙酒保会说“不行这不是你的钥匙。”
再进一步的问题
可以看到解锁是有两个操作先查看是否是自己的钥匙是的话再归还钥匙delete
但整个解锁操作并不是原子性的可能检查的时候是自己的而归还删除的时候已经是别人的了 比如说你刚获取到是自己的锁然后处于了一个很长的 GC…
四、Lua 脚本确保原子性
这时就需要 Lua 脚本来保证解锁的原子性因为 Redis 在执行 Lua 脚本时可以以原子性的方式执行保证了锁释放操作的原子性。
// 释放锁时先比较 unique_value 是否相等避免锁的误释放
if redis.call(get,KEYS[1]) ARGV[1] thenreturn redis.call(del,KEYS[1])
elsereturn 0
end这样就通过使用 SET 命令 加上 NX 和 EX 参数 以及 Owner 标志 和 Lua 脚本在 Redis 单节点上完成了分布式锁的加锁和解锁。
通过以上方式分布式锁的前三个特性 互斥性 、 锁失效机制以及对称性就基本解决了
那么对于高可用其实就是基于集群模式主从复制加上哨兵模式即可
详见之前文章
Redis实战篇——搭建主从复制 Redis原理篇——哨兵机制