深入Redis:分布式锁

在一个分布式的系统中,会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制,避免出现类似于“线程安全”的问题。

Java中的synchronize只能在当前线程中生效,在分布式的这种多个进程多个主机的场景下就无能为力了。此时就需要用到分布式锁。

分布式锁,本质上就是使用一个公共的服务器来记录加锁状态,这个公共的服务器可以是Redis,也可以是其他的组件(MySql或者Zookeeper等),也可以是自己写的一个服务。

基础实现

所有蓝色的模块,都是原先的服务器/客户端。现在加入一个橙色的Redis服务器作为分布式锁的管理器。

此时如果某客户端需要访问数据库,就需要先访问Redis,在Redis上设置一个键值对。设置value为1,而不是0。作此操作就可以对当前key加锁,操作完成后再把这个key删除。别的客户端需要访问这个key,发现Redis上已经有了这个键值对,就会阻塞等待或者放弃。

Redis中提供了setnx操作,正好适合这个场景:key不存在就设置,存在则直接失败。

过期时间

当服务器1加锁之后,意外宕机了,就会导致解锁操作一直不能执行,就可能引起其他服务器始终无法获取到锁的情况。为了解决这个问题,可以在设置key的同时引入过期时间,即这个锁最多持有多久就应该被释放。

Redis中提供了 set ex nx操作,可以在设置锁的时候同时把过期时间给设置进去。

校验ID

对于Redis中写入的加锁键值对,其他的节点也是可以删除的。(虽然不会主动删除,但是不排除遇到bug)。

为了解决上述问题,我们再引入一个校验ID,可以把设置的键值对的值,不在简单的设置成为一个1,可以设置成服务器的编号,如服务器1就设置成001。这样就可以在删除key的时候,先校验当前删除key的服务器是否是当初加锁的服务器,如果是才能真正删除。

看门狗(watch dog)

上述方案仍然存在一个重要的问题:如果如果任务还没执行完,key就过期了怎么办?

所谓的watch dog,本质上是加锁的服务器(发起加锁的服务器)上一个单独的线程。通过这个线程来对锁过期时间进行续约。

初始情况下设置过期时间为 10s,同时设定看门狗线程每隔 3s 检测一次
那么当 3s 时间到的时候,看门狗就会判定当前任务是否完成:

  • 如果任务已经完成,则直接通过 lua 脚本的方式,释放锁(删除 key)
  • 如果任务未完成,则把过期时间重写设置为 10s

这样就不担心锁提前失效的问题了,而且另一方面,如果服务器挂了,看门狗线程也就随之挂了,此时无人续约,这个key自然就可以迅速过期,让其他服务器能够获取到锁。

Redlock算法

实践中的Redis一般是以集群的方式部署的,就可能出现某些极端情况:

服务器1向master节点进行加锁操作,这个写入key的过程刚刚完成,master挂了。

slave节点升级成了新的master节点,但是由于刚刚写入的这个key还没有同步给slave,此时相当于服务器1的加锁操作形同虚设,服务器2仍然可以进行加锁。

我们引入一组 Redis 节点.其中每一组 Redis 节点都包含一个主节点和若干从节点,并且组和组之间存
储的数据都是一致的,相互之间是"备份"关系(而并非是数据集合的一部分,这点有别于 Redis cluster).
加锁的时候,按照一定的顺序,写多个master节点,在写锁的时候需要设定操作的"超时时间".比如
50ms.即如果 setnx 操作超过了 50ms 还没有成功,就视为加锁失败。

如果给某个节点加锁失败,就立即再尝试下一个节点。当加锁成功的节点数超过总节点数的一半,才视为加锁成功。
同理,释放锁的时候,也需要把所有节点都进行解锁操作。(即使是之前超时的节点,也要尝试解锁,尽量保证逻辑严密)。简而言之,Redlock算法的核心就是,加锁操作不能只写给一个Redis节点,而要写个多个。分布式系统中任何一个节点都是不可靠的。最终的加锁成功结论是"少数服从多数的"。由于个布式系统不至于大部分节点都同时出现故障,因此这样的可靠性要比单个节点来说靠谱不少。

至此,Redis告一段落~18篇文章不是Redis的完结,是新的篇章的开始~

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值