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深度历险--核心原理与应用实践》

posted @ 2024-06-14 22:52  东山絮柳仔  阅读(14)  评论(0编辑  收藏  举报