Redis基础知识(学习笔记3--Redlock)
讨论的问题:Redis 主从架构锁失效(丢失)
1.背景描述
当主节点挂掉时,从节点会取而代之,但是客户端却没有明显感知。比如,原先第一个客户端在主节点中成功申请了一把锁,但是这把锁还没来得及同步到从节点,主节点突然挂掉了,然后从节点变成了主节点,这个新的主节点内部没有这个锁,所以当另一个客户端发送请求加锁时,立即就批准了。这样就会导致系统中同样一把锁被两个客户端同时持有,不安全性由此产生。
问题示意图如下:
即使在Sentinel集群下,此问题依然存在。
此问题在主从failover时才会发生,并且持续时间会很短,很多时候,对业务无明显影响。
2. Redlock方案 Redlock实现原理
Redlock方案,需要多个Redis示例,这些示例之间相互独立,没有主从关系。通很多分布式算法一样,Redlock也使用“大多数机制”。
3.redlock-py----Realock算法
import redlock addrs = [{ "host" : "localhost", "port" : 6379, "db" : 0 }, { "host" : "localhost", "port" : 6479, "db" : 0 }, { "host" : "localhost", "port" : 6579, "db" : 0 }] dlm = redlock.Redlock(addrs) sucess = dlm.lock("user-lck", 5000) if sucess: print 'lock sucess' dlm.unlock('user-lck') else: print 'lock failed'
加锁时,它会向过半节点发送set(key, value, nx=True, ex=xxx) 指令,只要过半节点set成功,就认为加锁成功。释放锁时,需要向所有节点发送del指令。
生产过程,还需要考虑出错重试、时钟漂移等细节问题。
4.坏处
(1)需要多台Redis实例;
(2)因为Redlock需要向多个节点进行读写,意味着其相比单实例Redis的性能会下降。
特别是,当某一个节点挂掉,其成功写入的返回时间明显加大了。这是要特别消失程序对写入redis超时时间的设置。(即redis还在写入,但是redis客户端已经认为写入超时了)。
(3)极端情况,Redis故障或重启,可能导致锁丢失。
例如,Redis实例 其将数据fsync到磁盘的策略为【appendfsync everysec 即每秒fsync一次】,即在故障时,可能会丢失1秒钟数据。
此时有A实例;B实例;C实例。
client请求,将数据写入到了A实例和B实例了,C未写入,并且A已经fsync磁盘了,B尚未fsync到磁盘。但是很不巧,B故障了,或重启了,那么B的数据丢失了。
这个时候,如果有新的请求,那么B和C可能接收-设置同样的key,这时候,对B而言,就像前面的key没有出现过一样,它忘记了。此时就可能出现“超卖”的问题。
当然,在【appendfsync always: 每次有新命令追加到AOF文件时,就执行一次fsync】,就不会出现重启,丢命令了。但是安全代码的成本就是慢和高消耗。
学习参阅声明
《Redis深度历险--核心原理与应用实践》