当前位置: 首页 > news >正文

Redis分布式锁:从“能用”到“好用”,中间差了多少细节?

redis分布式锁安全吗?

1、为什么需要分布式锁

  与分布式锁对应的是【单机锁】,在写多线程时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来【互斥】,以确保共享变量的正确性,使用范围是在同一个进程中。

  若有多个进程需要同时操作一个共享资源,怎么实现互斥呢?现在的业务应用通常是微服务架构,若多个进程需要修改mysql的同一行记录时,为了避免操作乱序导致数据错误,这里就要使用【分布式锁】来解决了。

  这里的做法是要有一个外部系统,当两个请求来时只会给一个进程返回成功,另一个等待。这个外部系统可以用mysql、redis或zookeeper,为了追求更好的性能,我们这里通常使用redis或Zookeeper。

2、 分布式锁怎么实现

  要实现【分布式锁】,就必须要有互斥的能力。我们可以使用SETNX命令,SET if Not eXists,若key不存在才会设置它的值。此时只有一个请求能成功获取锁,操作完成后还要及时释放锁。如何释放?——使用DEL命令删除这个key。

  但有个很大的问题:1)程序处理业务逻辑异常,没及时释放锁;2)进程挂了,没机会释放锁。那么这个客户端就会一直占用这个锁,造成【死锁】。

3、如何避免死锁

  在申请锁时给key设置一个过期时间。这样无论客户端是否异常,这个锁都可以在x秒后自动释放。但这样还是有问题,现在的加锁和设置过期是两条命令,没有原子执行,还是有可能发生【死锁】。  

  在redis2.6.12版本之后,扩展了SET命令的参数, SET lock 1 EX 10 NX,这样就可以同时加锁和设置过期时间了。

  那如果存在以下问题:1)对锁过期时间评估不准,实际上不够。2)客户端在释放锁没有检查这把锁是否还归自己持有,所就会发生释放别人锁的操作

4、锁被别人释放怎么办

  客户端在加锁时,设置一个只有自己直到的【唯一标识】进去。例如可以是自己的线程ID,也可以是UUID(随机且唯一),这样在释放的时候就要先判断锁是否还归自己持有。这里释放锁用的是GET+DEL两条命令,又会有原子性问题。所以我们就可以引入Lua脚本,让redsi执行。因为redis处理每一个请求都是单线程的,在执行lua脚本时,其他请求必须等,直到lua被处理完成。

5、评估锁过期时间

  加锁时,先设置一个过期时间,然后开启一个【守护线程】,定时去检测这个锁的失效时间,若锁快要过期了,共享资源还未完成,那么久自动对锁进行【续期】。

  如果是Java技术栈,有一个库已经把这些工作封装好了:Redisson。它是一个基于Java实现的Redis SDK客户端,在使用分布式锁时,他就采用了自动续期的方案来避免锁过期,这个守护线程我们一般叫做看门狗线程。此外,这个库还封装了很多功能:1)可重入锁;2)乐观锁;3)公平锁;4)读写锁;5)redlock等。

  以上分析的都是在【单redis实例下可能出现的】问题,没有涉及到redis的部署架构细节。而我们工作中通常会采用主从集群+哨兵的模式部署,那当发生【主从切换】时,这个分布式锁还安全吗?(场景:客户端1在主库上执行SET,加锁成功-->此时主库宕机,SET命令还未同步到从库上-->从库被哨兵提升为主库,这个锁在新的主库上丢失了!!

6、redlock真的安全吗

  首先,redlock的方案基于两个前提:1)不再需要部署从库和哨兵实例,只部署主库;2)主库要部署多个,官方推荐至少5个实例。

  也就是说,要使用redlock,至少需要部署5个redis实例,而且都是主库,他们之间没有任何关系,都是一个个孤立的实例。

  整体流程:

  • 客户端先获取【当前时间戳T1】
  • 客户端以此向这5个redis实例发起加锁请求,且每个请求会设置超时时间若某个一个实例加锁失败,就立即向下一个redis实例申请加锁。
  • 若客户端从>=3个以上redis实例加锁成功,则再次获取【当前时间戳T2】,若T2-T1 < 锁过期时间,此时认为客户端加锁成功,否则认为加锁失败。
  • 加锁成功,去操作共享资源。
  • 加锁失败,向全部节点发起释放锁的请求(lua)

  1)为什么要在多个实例上加锁?——本质上是为了保障在部分实例宕机时,剩余的实例加锁成功,整个锁服务依旧可用。

  2)为什么大多数加锁成功,才算成功?——多个redis实例一起来用,其实组成了一个分布式系统。在这里总会出现异常节点,所以我们需要考虑异常节点达到多少个也依旧不会影响整个系统的【正确性】。

  3)为什么步骤3加锁成功后,还要计算加锁的累计耗时?——因为操作的是多个节点,耗时肯定比单个实例更久,且因为是网络请求,可能存在延迟、丢包等。所以即使大多数加锁成功,若枷锁的累计耗时以及超过了锁的【过期时间】,那此时有些实例上的锁已经失效了,这个锁就没意义了。

  4)为什么释放锁,要操作所有节点?——在某一redis节点加锁时,可能因为网络原因导致加锁失败。在释放锁时,不管有没有加锁成功,都要释放所有节点的锁。

7、redlock存在问题

  性能与复杂度高:需要向多个redis节点发起加锁请求,网络延迟和节点通信成本高于单节点锁,且需处理部分节点超时的重试逻辑。

  时钟依赖风险:依赖各节点时钟大致同步,若某节点时钟跳变,可能导致幻读锁(已过期的锁被判定为有效)

  资源占用大:需维护多节点集群,增加部署和运维成本,对中小型应用不够友好。

  适用场景:分布式系统中,单节点redis锁可能因主从切换、网络分区失效,redlock通过多节点投票机制降低锁丢失风险。容忍一定性能损耗,可以接收多节点通信开销。

8、Zookeeper

  是一个分布式协调服务,基于ZAB协议(原子广播协议)提供强一致性的分布式锁、配置管理、服务发现能力。其核心数据模型为树形结构,节点可存储少量数据,并支持监听机制。

  核心功能:

  • 分布式锁:通过创建临时顺序节点实现,客户端监听前序节点释放事件,避免惊群效应。
  • 配置中心:将配置存储在ZNode,客户端监听节点变更,实时获取最新配置。

  总之,强一致性协调服务,原生支持分布式锁和监听机制,适合对一致性要求高的分布式系统,但部署维护成本高于Redis。

 

参考:水滴与银弹

 

http://www.jsqmd.com/news/39432/

相关文章:

  • 为什么你的JavaScript代码总是出bug?这5个隐藏陷阱太坑了!
  • [电调]AM32电调调参系列 —— Complementary PWM参数的作用与分析
  • Zabbix监控mysl数据库配置
  • 嵌入式学习笔记-Chapter4
  • Java 线程同步与线程间通信
  • 2025年惠州高端中医馆品牌权威推荐榜单:老中医问诊/代煎中药/老中医调理身体品牌精选
  • HarmonyOS ArkTS卡片开发:多种方式实现卡片信息刷新
  • 可视化图解算法68:数组中出现次数超过一半的数字
  • 2025年惠州线下媒体公司权威推荐榜单:楼宇视频广告/社区广告/社区媒体广告源头公司精选
  • 题解:P9052 [PA 2021] Areny
  • Copula函数的参数估计与拟合
  • 深度学习进阶(八)——AI 操作系统的雏形:AgentOS、Devin 与多智能体协作 - 实践
  • 服务保护
  • [电调]AM32电调调参系列 —— PWM Frequency参数分析
  • 【MySQL】数据库表的CURD(二) - 详解
  • 2025年国内自助入住系统公司排行榜:智能化酒店解决方案全面解析
  • 2025年国内自助入住系统公司TOP5权威推荐:智慧住宿新选择
  • 2025年11月安徽合肥最值得信赖的十大自助入住系统企业权威推荐
  • 基于AdaBoost算法的人脸检测原理与实现
  • 内蒙古太空菌酸奶厂家,厚乳老酸奶厂家排名,希腊酸奶公司排行榜,奶皮子糖葫芦生产厂家,干咽酸奶厂家,冷萃酸奶源头工厂,口碑推荐!
  • 把云南交给我:一名向导的专业承诺
  • vs一打开文件上传的页面, 即使不上传文件 然后关闭页面 vs就退出调试模式了
  • PG系列:并行创建索引
  • 透明液晶展示柜鞍山批发,实时报价享特价省成本
  • 2025年行业内专业的安检门源头厂商推荐榜单,演唱会安检门/行李安检门/工厂安检门/车站安检机实力厂家口碑推荐榜
  • OLIDWORKS 2025 SP5.0 多语言完整版 10 月更新,解锁三维机械设计新高度
  • 推荐4款内网穿透工具,轻松突破内网限制
  • 2025年不锈钢逆流闭式冷却塔定做厂家权威推荐榜单:密闭式冷水塔/印染废水用封闭式凉水塔/印染废水用闭式冷却塔源头厂家精选
  • bluetooth matlab GFSK 调制解调,误码率统计
  • without updating the macOS to figure out the Markdown import to Mac Note app