redis分布式锁的思考

在描述设计之前,先提出三个属性,这三个属性是实现高效分布式锁的基础。

安全属性:互斥,不管任何时候,只有一个客户端能持有同一个锁。
效率属性A:不会死锁,最终一定会得到锁,就算一个持有锁的客户端宕掉或者发生网络分区。
效率属性B:容错,只要大多数Redis节点正常工作,客户端应该都能获取和释放锁。

有几个疑惑:

1 单实例的failover场景,如何保证一致性

在我们的系统架构里存在一个单点故障,如果Redis的master节点宕机了怎么办呢?有人可能会说:加一个slave节点!在master宕机时用slave就行了!但是其实这个方案明显是不可行的,因为这种方案无法保证第1个安全互斥属性,因为Redis的复制是异步的。 总的来说,这个方案里有一个明显的竞争条件(race condition),举例来说:

a. 客户端A在master节点拿到了锁。
b. master节点在把A创建的key写入slave之前宕机了。
c. slave变成了master节点 4.B也得到了和A还持有的相同的锁(因为原来的slave里还没有A持有锁的信息
即使使用官方推荐的方案,感觉依然存在上述问题

 SET resource_name my_random_value NX PX 30000
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

这种情况如何避免,网上有说通过双写来实现,这是一种方案,牺牲性能保证可以性,不知道是否还有其他方案。

2 分布式(多实例)环境,官方方案是否性能太差

a. 获取当前时间(单位是毫秒)。

b. 轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。比如如果锁自动释放时间是10秒钟,那每个节点锁请求的超时时间可能是5-50毫秒的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。

c. 客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁(在这里是3个),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。

d. 如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。

e. 如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,客户端都会到每个master节点上释放锁,即便是那些他认为没有获取成功的锁。

集群环境下要过半的节点获取到锁,才认为成功,是否效率太差。

参考资料:
https://redis.io/topics/distlock
http://ifeve.com/redis-lock/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值