这篇是Redis 学习笔记系列的高可用篇,也就是实战篇,所有的redis 系类更新首先是日常工作笔记和Redis 源码系列。[先挖坑,后面慢慢填吧,雾...]

分布式锁的实现要点是什么?

分布式锁实现四要点:

  • 互斥性
  • 抗死锁性
  • 对称性
  • 可靠性

为什么要引入Owner 概念?

  • 因为不加入Owener -- 也就是锁的持有者信息,那么锁就无法实现堆成性,即一把锁的加解锁可以是凉饿用户,分布式锁得对称性也就无法保障

如何保障事务原子性?

redis 本身提供有事务操作,但是不保障原子性,这个事务执行总如果中间有错误,事务不会打断也不会回滚而是就绪执行剩下得事务。无法保障事务原子性

目前主流做法是使用Lua 脚本作事务脚本,用脚本操作redis 来保证事务. 因为redis 核心业务时单线程的,在执行Lua 脚本时会整脚本当作一个作业事务来处理,所以能保证原子性,但是Lua 事务粗错不会回滚,只会中断。

可靠性如何保障

异常情况: 节点挂了、业务时间超时、网络延迟...

对于挂了

  • 主从容灾,从节点挂有其他节点,主节点挂有从节点顶上变主节点....
    • 主从切换可以使用哨兵模式 主从模式再同步数据时会有一定的数据延时,一致性保障不如分布式强
  • 分布式多机部署
    • 也就是所谓的 分布式存储方案,比如引入RedLock,但是节点个数建议是单数个

RedLock

是什么?

一种分布式锁算法,由 Redis 的作者设计,用于在分布式系统中实现可靠的锁机制。它的设计解决了单一 Redis 实例作为分布式锁可能出现的单点故障问题。-- 也就是客户端从master 获取锁后 master未来的及将锁信息同步给其他节点就挂了,新节点顶替,另一个客户端获取相同得资源获取成功得问题。

实现原理:

  • 多节点加锁: RedLock 在多个独立的 Redis 实例上同时尝试获取锁。通常建议使用奇数个 Redis 实例(如 5 个),以确保系统具有较好的容错性。
  • 多数节点同意: 系统只有在获得了大多数 Redis 实例的锁(即 N/2 + 1 个节点,N 为节点总数)之后,才认为成功获取了分布式锁。这样即使部分 Redis 实例发生故障,整体锁服务仍然可用。
  • 时间同步: 为防止客户端在持有锁的过程中发生故障而导致锁无法释放,RedLock 会在获取锁时设置一个超时时间。如果客户端在锁超时之前未能完成任务并释放锁,其他客户端可以在锁超时后重新尝试获取。 -- 针对业务超时未完成导致锁被自动过期释放这一为题可引入看门狗,看门狗发定期检查业务线程作业情况,发现仍未完成,则续期锁
  • 锁释放: 释放锁时,客户端需要向所有 Redis 实例发送释放锁的命令,以确保所有实例上的锁都被清除。

工作原理

  1. 获取当前unix毫秒时间戳(业务开始时间戳),设置锁TTL(TTL > 业务耗时 + 成功获取锁耗时 + 时钟漂移)。
  2. 使用相同得kv值, 依次向各分节点获取锁(获取前设置这次向该节点获取锁得超时时间,避免死等,超时放弃,改向下一个节点重复此操作)更新锁获取时间戳。
  3. 锁获取时间戳减业务开始时间戳 = 锁申请耗时时间戳
  4. 业务锁获取成功(获取成功条件见下,假设有单数各节点N,成功获取锁的节点个数M)
    1. M >= (N/2) + 1
    2. 剩余业务可用时间 > (锁TTL - 锁获取总时间 - 时钟漂移) 比如:TTL 是10s,获取所有锁用了 2s,则真正锁有效时间为 8s;
  5. 如果锁获取失败 向所有节点发送解锁操作(包括获取失败的节点,因为不知道时网络原因导致超时判断的失败还是真失败...). -- 必要时可以使用双删(删了后等一会再删),或者引入看门狗
  6. 锁获取失败重试;等一会再来获取看看(重试次数应有限制避免过度浪费资源)...

REDLOCK 真的可靠吗? -- NCP 可靠性探讨

N

N - network delay 网络延迟;这里讲的时获取锁因为网络延迟导致时间关系问题,以及怎么直到获取成功?

  • 设置锁TTL 时可以多预估(冗余)一段时间
  • redis 会有回包反馈锁获取情况
  • 设置获取等待超时时间,超时算失败

总的来说能一定程度缓解网络延迟问题

P

P - Process Pause (进程阻塞/暂停); 这里讲的时获取锁后,业务处理超时(比如业务处理中GC,中间被更高优先级的作业任务打断挂起...), 之后Redis中的锁超时了(这种情况可以使用看门狗,但看门狗不是万能的比如作业进程不会看门口了,看门狗以为作业进程死了,那没得解),之后这个超时得进程从超时中恢复了过来,另一个进程申请走了锁,这时后就会有看起来凉饿进程都获取到锁得情况。这种也算无解

C

C - Clock Drift (时钟漂移);为了方便这里假设一种极端情况(但其实概率很小),假设有5个节点,5个节点都发生了时钟漂移(系统时钟突然从某个时间突然变到某个时间),导致锁失效,这是后另一个进程获取了锁,这样就会看起来两个进程都拿到了锁。这中情况也算是无解。

总结

RedLock 其实也扛不住上面极端得论述情况,所以要实现一个相对可靠的分布式锁,还需要根据业务出发,业务本身要可重入,幂等才行。

PS Red Lock 是一种比较重的锁方案,一般业务很少用到。