分布式锁的理解,以及redis分布式锁的实现

分布式锁

分布式锁,是一种跨进程的跨机器节点的互斥锁,它可以用来保证多机器节点对于共享资源访问的排他性。
我觉得分布式锁和线程锁本质上是一样的,线程锁的生命周期是单进程多线程,分布式锁的生命周期是多进程多机器节点。
在本质上,他们都需要满足锁的几个重要特性:
  • 排他性,也就是说,同一时刻只能有一个节点去访问共享资源。
  • 可重入性,允许一个已经获得锁的进程,在没有释放锁之前再次重新获得锁。
  • 锁的获取、释放的方法
  • 锁的失效机制,避免死锁的问题

 所以,我认为,只要能够满足这些特性的技术组件都能够实现分布式锁。

关系型数据库

关系型数据库,可以使用唯一约束来实现锁的排他性,如果要针对某个方法加锁,就可以创建一个表包含方法名称字段,并且把方法名设置成唯一的约束。那抢占锁的逻辑就是:往表里面插入一条数据,如果已经有其他的线程获得了某个方法的锁,那这个时候插入数据会失败,从而保证了互斥性。 这种方式虽然简单啊,但是要实现比较完整的分布式锁,还需要考虑重入性、锁失效机 制、没抢占到锁的线程要实现阻塞等,就会比较麻烦。

Redis实现分布式锁

Redis 实现

Redis 实现分布式锁主要利用 Redis setnx 命令

实现原理

当执行 SETNX 命令时,它会尝试将指定的键 key 设置为给定的值 value ,但只有在键 key 不存在时,才会进行设置。如果键不存在,则设置成功,返回值为 1 ;如果键已经存在,则设置失败,返回值为 0 。需要在业务上针对返回值手动进行分支判断实现上锁逻辑。
Redis,它里面提供了 SETNX 命令可以实现锁的排他性,当 key 不存在就返回 1,存在就返回 0。然后还可以用 expire 命令设置锁的失效时间,从而避免死锁问题。当然有可能存在锁过期了,但是业务逻辑还没执行完的情况。 所以这种情况,可以写一个定时任务对指定的 key 进行续期。
Redisson 这个开源组件,就提供了分布式锁的封装实现,并且也内置了一个 Watch Dog 机制来对 key 做续期。 我认为 Redis 里面这种分布式锁设计已经能够解决 99%的问题了,当然如果在Redis搭建了高可用集群的情况下出现主从切换导致 key 失效,这个问题也有可能造成多个线程抢占到同一个锁资源的情况,所以 Redis 官方也提供了一个 RedLock 的解决办法,但是实现会相对复杂一些。
不足之处:
  • 只能在单个 Redis 节点上实现分布式锁,不适用于集群架构
  • 锁的功能单一,需要手动维护上锁逻辑
  • 有死锁风险,无法实现锁超时自动释放
  • 不支持锁重入

Redison 实现

Redison 实现的分布式锁基于 Redis Lua 脚本 Redis setnx 指令 来实现
Redisson 的分布式锁支持多种功能,例如可重入锁、公平锁、读写锁等。

主从一致性

主从一致性是指在 Redisson 中,分布式锁的主节点和从节点之间的数据一致性。当一个Redisson 分布式锁实例在主节点上获取锁成功后,该锁状态会被同步到所有的从节点上,确保所有节点对这个锁的状态是一致的。这样,即使主节点发生故障或者网络分区等情况导致主节点不可用,其他从节点仍然可以继续提供对这个锁的服务

解决方法

RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁(n / 2 + 1),避免在一个redis实例上加锁

如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁  

好处
  • 强大的容错性和高可用性Redison 通过 Redisson Redis Sentinel 自动故障转移和 RedisCluster 自动分片功能
  • 看门狗机制:每隔(releaseTime / 3)的时间做一次锁续期,根据业务复杂度动态调整锁超时释放时间,如果状态异常,则视为故障发生,不再续期,超时释放锁,避免死锁
  • CAS优化:支持原地自旋等待获取锁,减少线程上下文交换提高CPU利用率
  • 线程安全:加锁、设置过期时间等操作都是基于lua脚本完成,确保操作原子性
  • 锁可重入:利用hash结构记录线程id和重入次数

总结

分布式锁应该是一个 CP 模型,而 Redis 是一个 AP 模型,所以在集群架构下由于数据的一致性问题导致极端情况下出现多个线程抢占到锁的情况很难避免。那么基于 CP 模型又能实现分布式锁特性的组件,我认为可以选择 Zookeeper 或者etcd,
  • 在数据一致性方面,zookeeper 用到了 zab 协议来保证数据的一致性,etcd用到了 raft 算法来保证数据一致性。
  • 在锁的互斥方面,zookeeper 可以基于有序节点再结合 Watch 机制实现互斥和唤醒,etcd 可以基于 Prefix 机制和 Watch 实现互斥和唤醒。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值