分布式基础——几种常见的分布式锁

分布式锁

在单机场景下,可以使用语言的内置锁来实现进程同步,如 synchronizedLock等。但是在分布式场景下,需要同步的进程可能位于不同的节点上,那么就需要使用分布式锁。

分布式锁:是控制分布式系统不同进程共同访问共享资源的一种锁的实现。

数据库的唯一索引

向表中插入一条唯一索引的记录,此时相当于加锁,释放锁时删除这条记录。唯一索引可以保证该记录只被插入一次,那么就可以用这个记录是否存在来判断是否处于锁定状态。

存在以下几个问题:

  • 锁没有失效时间,解锁失败的话其它进程无法再获得该锁;
  • 只能是非阻塞锁,插入失败直接就报错了,无法重试;
  • 不可重入,已经获得锁的进程也必须重新获取锁。

Redis 的 SETNX 指令

使用 SETNX(set if not exist)指令插入一个键值对,如果 Key 已经存在,那么会返回 False,否则插入成功并返回 True。

SETNX 指令和数据库的唯一索引类似,保证了只存在一个 Key 的键值对,那么可以用一个 Key 的键值对是否存在来判断是否存于锁定状态。

EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了数据库唯一索引实现方式中释放锁失败的问题。

缺点:

  • setnx和expire分两步执行,非原子操作;若setnx执行成功,但expire执行失败,就可能出现死锁。如果执行完setnx加锁,正要执行expire设置过期时间时,进程crash掉或者要重启维护了,那这个锁就一直存在了,别的线程永远获取不到锁了。
  • 不支持阻塞等待、不可重入

Redis set的扩展命令(set ex px nx)

# 一条命令保证原子性执行
127.0.0.1:6379> SET lock value EX 10 NX
OK
# 加锁与设置过期时间原子性执行

存在问题:

  • 锁过期释放了,业务还没执行完。
  • 锁被其他线程误释放。(可以使用lua脚本释放,但第一个问题依旧无法解决)

Redisson

以上的方案可能存在锁过期释放,业务没执行完的问题。其实我们可以给获得锁的线程开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在就自动对锁的过期时间延长,防止锁过期提前释放

Redisson 实现的原理就是基于看门狗机制

只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此使用Redisson能够解决锁过期释放,业务没执行完问题。并且 Redisson 还是可重入锁,底层依靠 lua 脚本支持。

Redis 的 RedLock 算法

Redis一般都是集群部署的,假设数据在主从同步过程,主节点挂了,Redisson 使用看门狗(守护线程)“续命”的方案可能会出现问题。

  1. 如果线程一在Redis的master节点上拿到了锁,将键值对写入 redis 的 master 节点
  2. 但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障
  3. Redis 触发故障转移,一个slave节点就会升级为master节点,此时新的 master 并不包含线程1写key
  4. 因此线程2尝试获取同个key的锁也可以成功拿到锁,但线程一也已经拿到锁了,锁的安全性就没了。

上述问题的根本原因主要是由于 redis 异步复制带来的数据不一致问题导致的,因此解决的方向就是保证数据的一致。为了解决这个问题,Redis作者提出一种高级的分布式锁算法:Redlock。Redlock核心思想是这样的:

使用了多个 Redis master 实例来实现分布式锁,这是为了保证在发生单点故障时仍然可用。

  • 尝试从 N 个互相独立 Redis master 实例获取锁;
  • 计算获取锁消耗的时间,只有时间小于锁的过期时间,并且从大多数(N / 2 + 1)实例上获取了锁,才认为获取锁成功;
  • 如果获取锁失败,就到每个实例上释放锁。

也就是说,该方案为了解决数据不一致的问题,直接舍弃了异步复制,只使用 master 节点,同时由于舍弃了 slave,为了保证高可用性,引入了 N 个节点,官方建议是 5。


参考资料

CS-Notes/分布式.md at master · CyC2018/CS-Notes (github.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值