分布式锁——Redis分布式锁

概述

在高并发环境下,必然会面临多线程对共享资源的竞争问题,如果不进行控制会出现一些异常行为。单机环境下可以使用Synchronized、ReentrantLock等JDK提供的锁来实现多线程对共享资源的互斥访问,但现在的应用大都是集群部署,针对这种跨JVM的情况如何实现来解决互斥访问的问题?这就需要用到分布式锁来进行控制。常见的分布式锁实现方式主要有数据库实现、Redis实现、Zookeeper实现,今天主要对Redis分布式锁进行探究。

Redis 分布式锁

1、加锁流程

  • SetNX key value 加锁
    当键不存在时,对键加锁成功并返回,当键存在时返回失败。

  • Expire key timeout 设置超时时间
    设置key的超时时间,可以保证异常情况下(如一个获取锁的线程在执行任务的时候挂掉,来不及释放锁)资源不会被永远锁住。

  • 存在的问题
    setNX、Expire两个命令并不是一个原子操作,因此如果在设置过期时间的时候线程挂掉了,会导致锁永远不会释放。
    分布式锁——Redis分布式锁_第1张图片

  • 加锁设置超时的原子操作
    Redis 2.8版本之前可以通过使用 Redis Lua脚本来解决,Redis 2.8版本之后提供了设置加锁、超时的原子性命令。

SET key value [expiration EX seconds|PX milliseconds] [NX|XX]

EX seconds:表示过期时间为second秒
PX milliseconds:表示过期时间为milliseconds毫秒
NX:键不存在时才进行设置操作
XX:只有键存在时才进行设置操作

2、解锁流程(DEL key)

锁超时——误删锁

线程A获取到锁且设置了过期时间是30秒,因为执行流程太耗时等原因导致到了过期时间线程A还在继续执行,这个时候A持有的锁就会被超时释放,这时线程B可以成功获取锁并执行自己的流程,这个时候A执行完并执行释放锁的操作,但此时释放的是线程B持有的锁,导致线程B的锁被误删,从而导致出现不可预知的意外情况。
分布式锁——Redis分布式锁_第2张图片
解决方案:

在释放锁之前如果可以对锁进行判断,如果要释放的锁是自己加的锁则可以释放,如果不是则不执行释放锁的操作。那么如何判断要释放的锁是不是添加的锁呢?这里可以通过保存版本号等方式来实现这个过程。但是判断和释放这两个操作并不是原子性的,因此还要通过Lua脚本来实现这两个操作的原子性。
加锁的时候 value 值可以设置为一个有意义的值如版本号、uuid、机器+线程编号等字段,解锁时通过判断value值判断自己是不是锁的创建者。

锁超时——并发访问

线程A的锁超时后,此时线程B可以获得锁,线程A和线程B就会并发执行,导致异常。
分布式锁——Redis分布式锁_第3张图片
解决方案:
一、将锁的过期时间设置的足够长,确保线程能够执行完所有的业务逻辑后才会出现过期的情况。
二、为获取锁的线程增加守护线程,为将要过期但未释放的锁增加有效时间。

3、脑裂问题

脑裂:是指在主从集群中,同时是有两个主节点吗,都能接收请求。

发生脑裂的原因?(原主库假故障导致的脑裂)

  • 因为网络等原因,导致Redis master节点和哨兵sentinel集群处于不同的网络分区,因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点,导致脑裂问题。
    分布式锁——Redis分布式锁_第4张图片

解决脑裂的方法

Redis 提供了两个配置项来限制主库的请求处理,分别是 min-slaves-to-write 和 min-slaves-max-lag。

  • min-slaves-to-write:设置了主库能进行数据同步的最少从库数量
  • min-slaves-max-lag:设置了主从库间进行数据复制时,从库给主库发送ACK消息的最大延迟(以秒为单位)

把 min-slaves-to-write 和 min-slaves-max-lag 这两个配置项搭配起来使用,分别给它们设置一定的阈值,假设为 N 和 T。这两个配置项组合后的要求是,主库连接的从库中至少有 N 个从库,和主库进行数据复制时的 ACK 消息延迟不能超过 T 秒,否则,主库就不会再接收客户端的请求。

即使原主库是假故障,它在假故障期间也无法响应哨兵心跳,也不能和从库进行同步,自然也就无法和从库进行 ACK 确认了。这样min-slaves-to-write 和 min-slaves-max-lag 的组合要求就无法得到满足,原主库就会被限制接收客户端请求,客户端也就不能在原主库中写入新数据了

脑裂对Redis分布式锁的影响

脑裂时可能发生两个客户端持有同一把锁的异常情况。
分布式锁——Redis分布式锁_第5张图片
参考链接
极客时间Redis核心技术与实战
分布式锁的实现之Redis篇

你可能感兴趣的:(分布式,redis,分布式锁)