分布式锁

来自智得网
跳转至: 导航、​ 搜索

简介

在单机环境下,锁一般通过CAS方式实现,通过锁定的时机或者范围一般分为悲观锁和乐观锁,在操作开始之前执行锁定操作一定成为称之为悲观锁,在提交的时候才可以加锁进行校验成为乐观锁。

在集群环境下,本机锁无法和集群内其他节点实现互斥,会出现业务逻辑错误,分布式锁就是集群场景下可以实现互斥能力的结构体。

原理

分布式锁的实现类型

锁的实现例如CAS本质上还是通过修改共享数据来实现的,所以分布式锁的本质也是修改分布式场景下的共享数据。

根据共享数据的不同,分布式锁可以通过Redis,数据库,Zookeeper等实现。

Redis

Redis锁的实现方式是通过Redis客户端向Redis写入数据的方式的方式,通过CAS实现写入的原子性来保证分布式锁实现的。

Redis加锁的命令一般是

//使用unique_value作为唯一性标识进行加锁操作 
//NX的含义是set为setnx(SET if not exist),实现原子性
//PX的含义是key的失效时间(分布式锁自动解锁的时间),避免手动解锁失败而长期hang住

SET lock_key unique_value NX PX 10000

Redis解锁的命令一般是

//ARGV[1]是加锁时候的唯一key,避免锁被其他线程释放

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

Redis分布式锁的问题如下,当Master节点不可用的时系统自动切换Slave(failover),但由于Redis的主从复制(replication)异步的原因,可能导致在failover过程中丧失锁的安全性。例如下面场景的客户端1和客户端2同时持有了同一个资源的锁。

  • 客户端1从Master获取了锁。
  • Master宕机,存储锁的key还未同步到Slave。
  • Slave升级为Master。
  • 客户端2从新Master获取到了对应同一个资源的锁。

RedLock

RedLock的加锁流程如下:

  • 客户端向N个Redis实例执行加锁操作,统计总耗时为TotalCost
  • 超过半数节点实例成功获取锁,并且锁的有效期大于TotalCost才表明加锁成功
  • 若加锁失败,则释放已成功获取的锁。
  • 若加锁成功,锁的有效时间=锁的超时时间-TotalCost