type
status
date
slug
summary
tags
category
icon
password
URL
文章来源说明

为什么需要分布式锁

  1. 多线程的时候,为了避免同时操作共享变量带来的数据问题,通常用互斥锁来实现,不过其范围在同一个进程
  1. 如果多个进程同时操作如恶化互斥
    1. 微服务中通常会有多个进程需要同时修改mysql同一个记录为了避免错误所以需要引入分布式锁来解决问题
    2. 想要实现分布式锁,一般都是借助外部系统,所有进程都去这个系统上申请加锁
    3. 外部系统可以是mysql,redis,zookeepr,但是为了性能当前主流都会选择redis和zookeepr
notion image

redis分布式锁实现

  1. 实现分布式锁需要互斥能力 setnx 刚好可以,但是这里的问题大家都知道可能会死锁
    1. 程序业务处理异常没有及时释放锁
    2. 进程挂了,没有机会释放锁
  1. 避免死锁,设置超时时间,2.6.12版本后redis 可以用1条命令来设置了,避免了原子问题
    1. 锁过期,和锁被别人释放问题
      1. 场景:
      2. 客户端1加锁成功,开始操作共享资源
      3. 客户端1操作共享资源时间过期,锁被自动释放
      4. 客户端2加锁成功,开始操作共享资源
      5. 客户端1执行完成,释放了客户端2的锁
    这里有两个问题
    1.锁过期,客户端1操作时间过长,导致锁自动释放被客户端2持有
    2 释放了别人的锁,客户端1释放了客户2的锁
     
    对于问题2可以在加锁时设置唯一标识,可以是自己线程id也可以是UUId
    之后释放锁先判断
    上面的命令get 和 del 是两步所以还有原子问题,所以需要lua脚本将其封装1个命令让redis 执行
     
    对于问题1,主要是锁过期无法判断,我们可以开1个线程,定时去检测这个锁失效时间,锁快过期时
    自动续期可见实现一把分布式锁需要考虑的东西挺多,好在redission 把这些工作都封装好了
    自动续期用的就是看门狗守护线程
    除此之外还实现一些其他功能
    • 可重入锁
    • 乐观锁
    • 公平锁
    • 读写锁
    • Redlock
     
     

    使用redission 后出现的问题

    一般用redis 我们都会用主从切换,主库异常宕机,从库变主库
    场景
    1. 客户端 1 在主库上执行 SET 命令,加锁成功
    1. 此时,主库异常宕机,SET 命令还未同步到从库上(主从复制是异步的)
    1. 从库被哨兵提升为新主库,这个锁在新的主库上,丢失了!
    为此,Redis 的作者提出一种解决方案,就是我们经常听到的 Redlock(红锁)
    但是红锁使用条件很苛刻,并且需要5个单节点,还要考虑机器时钟问题,一般不建议
     

    基于zookeeper的锁安全吗?

    如果你有了解过 Zookeeper,基于它实现的分布式锁是这样的:
    1. 客户端 1 和 2 都尝试创建「临时节点」,例如 /lock
    1. 假设客户端 1 先到达,则加锁成功,客户端 2 加锁失败
    1. 客户端 1 操作共享资源
    1. 客户端 1 删除 /lock 节点,释放锁
    你应该也看到了,Zookeeper 不像 Redis 那样,需要考虑锁的过期时间问题,它是采用了「临时节点」,保证客户端 1 拿到锁后,只要连接不断,就可以一直持有锁。
    而且,如果客户端 1 异常崩溃了,那么这个临时节点会自动删除,保证了锁一定会被释放。
    不错,没有锁过期的烦恼,还能在异常时自动释放锁,是不是觉得很完美?
    其实不然。
    思考一下,客户端 1 创建临时节点后,Zookeeper 是如何保证让这个客户端一直持有锁呢?
    原因就在于,客户端 1 此时会与 Zookeeper 服务器维护一个 Session,这个 Session 会依赖客户端「定时心跳」来维持连接。如果 Zookeeper 长时间收不到客户端的心跳,就认为这个 Session 过期了,也会把这个临时节点删除。可见,即使是使用 Zookeeper,也无法保证进程 GC、网络延迟异常场景下的安全性。
    好,现在我们来总结一下 Zookeeper 在使用分布式锁时优劣:
    Zookeeper 的优点:
    1. 不需要考虑锁的过期时间
    1. watch 机制,加锁失败,可以 watch 等待锁释放,实现乐观锁
    但它的劣势是:
    1. 性能不如 Redis
    1. 部署和运维成本高
    1. 客户端与 Zookeeper 的长时间失联,锁被释放问题
    💡
    有关Notion安装或者使用上的问题,欢迎您在底部评论区留言,一起交流~
     
     
    ElasticSearchIDEA热部署插件JRebel使用
    Loading...