分布式锁的概念

前言

在分布式系统中, 每个服务器都是一个单独的进程, 因为进程之间的执行顺序又是随机的, 很容易导致严重问题.

以买票系统为例, 如果没有分布式锁的话, 由于进程的随机性, 可能会导致一张票卖给两个人引发"超卖"问题. 所以引入分布式锁来解决:

例如当买票服务器1想进行买车次001的票时, 会先访问Redis, 寻找有没有其他服务器在买车次001的票, 如果没发现就在Redis上设置一个关于001的key. 此时如果其他服务器也想买001的票但是发现Redis上已经存在了这个key, 则不会再买票. 这样就达到了加锁的目的.

用Redis进行"加锁"的具体流程

利用Redis中的"set nx"

Redis中的"set nx"命令格式如下:

复制代码
SET key value NX

这样的效果是: 如果Redis上存在这样的Key就不会进行设置, 没有才会设置Key.

当以这样的方式进行"加锁"操作后, 我们同样需要对"锁"进行释放. 而利用del命令即可删除Key达到释放的效果.

为Key设定一个过期时间

如果一个服务器已经对Redis添加了Key, 但是这个服务器意外崩溃, 此时的"锁"还没有释放, 其他服务器只能进行等待. 为避免这一情况, 设置Key时需要添加一个"过期时间"的选项, 命令格式如下:

复制代码
SETNX key value NX EX (时间, 单位为秒)

避免这个服务器长时间占用"锁".

为服务器设置校验ID

有一种情况: 服务器1进行了set nx加锁了, 但服务器2执行了del释放了锁. 为避免这一情况, 需要对释放锁操作进行一个条件判定: 为所有服务器设置一个ID, 在释放锁时对服务器ID进行判定, 是否为加锁的服务器, 确定后再删除.

设置校验ID的流程如下(以伪代码形式说明):

引入Lua

根据上面设置服务器ID的过程中, 可以发现这个操作并非原子性的, 这就意味着可以被其他操作来"插队", 例如可能在验证的后另外一个服务器又进行了"set"操作, 当执行到del时就会释放另外一个服务器的锁了

为了解决这种问题, 采用Lua脚本的方式将这种非原子性的命令写入进去, 因为Redis在执行Lua脚本时是原子性的. 达到了事务的效果

写入Lua脚步执行的代码:

复制代码
if redis.call('get',KEYS[1]) == ARGV[1] then 
   return redis.call('del',KEYS[1]) 
else
   return 0 
end;

引入看门狗(watch dog)

在设置Key的过期时间时, 需要考虑到: 时间不能过短,防止服务器的操作未执行完就进行释放锁. 也不能设置时间过长,导致长时间占用锁,使其他服务器无法进行操作.

而引入看门狗机制可以有效解决问题: 在服务器中设置一个专门监视的线程, 如果快要到过期时间且服务器的操作还未结束, 那么将继续延长过期时间, 直到操作完成.

使用ReadLock算法

在使用Redis实现分布式锁时, 需要注意Redis节点的宕机, 这是致命性的. Redis也给出了对应办法

RedLock算法:

在Redis中使用"哨兵"机制, 实现主节点宕机,从节点晋升. 我们引入多 组 Redis 节点. 其中每⼀组 Redis 节点都包含⼀个主节点和若干从节点. 并且组和组之间存 储的数据都是⼀致的, 相互之间是 "备份" 关系(而并非是数据集合的⼀部分, 这点有别于 Redis cluster). 加锁的时候, 按照⼀定的顺序, 写多个 master 节点. 在写锁的时候需要设定操作的 "超时时间". 比如 50ms. 即如果 setnx 操作超过了 50ms 还没有成功, 就视为加锁失败.如果给某个节点加锁失败, 就⽴即再尝试下⼀个节点. 当加锁成功的节点数超过总节点数的⼀半, 视为加锁成功.

如上图, ⼀共五个节点, 三个加锁成功, 两个失败, 此时视为加锁成功. 这样的话, 即使有某些节点挂了, 也不影响锁的正确性. 而释放锁时同样需要对所有Redis服务器进行释放锁操作

相关推荐
Lansonli5 小时前
大数据Spark(七十九):Action行动算子countByKey和countByValue使用案例
大数据·分布式·spark
少许极端6 小时前
Redis入门指南(八):从零到分布式缓存-集群机制、缓存机制、分布式锁
redis·分布式·缓存·分布式锁
珠海西格15 小时前
“主动预防” vs “事后补救”:分布式光伏防逆流技术的代际革命,西格电力给出标准答案
大数据·运维·服务器·分布式·云计算·能源
小邓吖18 小时前
自己做了一个工具网站
前端·分布式·后端·中间件·架构·golang
曹天骄1 天前
基于 Cloudflare Worker 构建分布式测速调度系统:KV 与 D1 数据层设计实战教程
分布式·缓存
Prince-Peng1 天前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
曹天骄1 天前
基于 Cloudflare Worker + KV 构建高性能分布式测速调度系统(工程实战)
分布式
奋进的芋圆1 天前
Spring Boot 3 高并发事务与分布式事务企业级完整解决方案
spring boot·分布式
淡泊if1 天前
Kafka部署模式详解:从单机到分布式集群的核心选择
分布式·kafka