etcd 实战课
唐聪
腾讯云资深工程师,etcd 活跃贡献者
28449 人已学习
新⼈⾸单¥59
登录后,你可以任选3讲全文学习
课程目录
已完结/共 28 讲
开篇词 (1讲)
etcd 实战课
15
15
1.0x
00:00/00:00
登录|注册

21 | 分布式锁:为什么基于etcd实现分布式锁比Redis锁更安全?

思考题
etcd分布式锁
Redis分布式锁
分布式锁实现

该思维导图由 AI 生成,仅供参考

你好,我是唐聪。
在软件开发过程中,我们经常会遇到各种场景要求对共享资源进行互斥操作,否则整个系统的数据一致性就会出现问题。典型场景如商品库存操作、Kubernertes 调度器为 Pod 分配运行的 Node。
那要如何实现对共享资源进行互斥操作呢?
锁就是其中一个非常通用的解决方案。在单节点多线程环境,你使用本地的互斥锁就可以完成资源的互斥操作。然而单节点存在单点故障,为了保证服务高可用,你需要多节点部署。在多节点部署的分布式架构中,你就需要使用分布式锁来解决资源互斥操作了。
但是为什么有的业务使用了分布式锁还会出现各种严重超卖事故呢?分布式锁的实现和使用过程需要注意什么?
今天,我就和你聊聊分布式锁背后的故事,我将通过一个茅台超卖的案例,为你介绍基于 Redis 实现的分布锁优缺点,引出分布式锁的核心要素,对比分布式锁的几种业界典型实现方案,深入剖析 etcd 分布式锁的实现。
希望通过这节课,让你了解 etcd 分布式锁的应用场景、核心原理,在业务开发过程中,优雅、合理的使用分布式锁去解决各类资源互斥、并发操作问题。

从茅台超卖案例看分布式锁要素

首先我们从去年一个因 Redis 分布式锁实现问题导致茅台超卖案例说起,在这个网友分享的真实案例中,因茅台的稀缺性,事件最终定级为 P0 级生产事故,后果影响严重。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

etcd分布式锁相比Redis锁更安全的原因是什么?本文通过一个茅台超卖案例,对比了基于Redis实现的分布式锁和etcd分布式锁的优缺点。文章首先介绍了分布式锁的背景和重要性,然后通过茅台超卖案例分析了基于Redis实现的分布式锁存在的问题,如NX参数的作用、活性和高性能、高可用性等核心要素。文章指出,基于Redis实现的分布式锁存在安全性问题,如死锁、超卖等,需要注意原子性、唯一性等方面。最后,文章提出了etcd分布式锁相对于Redis锁更安全的原因,包括etcd的强一致性、高可用性和更适合复杂业务场景等特点。文章通过具体案例和技术要点,深入浅出地介绍了分布式锁的实现和安全性问题,对读者了解分布式锁的应用场景、核心原理以及安全性问题具有一定的指导意义。文章还介绍了ZooKeeper分布式锁和etcd分布式锁的实现方式,重点阐述了etcd分布式锁的安全性、互斥性、活性等方面。通过对比分析,文章强调了etcd分布式锁相对于Redis锁的优势,为读者提供了全面的技术视角和实践指导。 etcd自带的concurrency包为了帮助你简化分布式锁、分布式选举、分布式事务的实现,etcd社区提供了一个名为concurrency包帮助你更简单、正确地使用分布式锁、分布式选举。文章通过具体代码示例介绍了如何使用concurrency包创建Session和Mutex对象,并通过Lock和Unlock方法实现分布式锁的获取和释放。同时,文章深入解析了Mutex对象的Lock方法的实现原理,以及未获得锁的client是如何通过Watch机制进行等待的。最后,文章通过对Redis分布式锁实现问题、RedLock分布式锁和etcd分布式锁的技术点进行了总结,强调了etcd分布式锁的安全性、互斥性和活性等优势,为读者提供了全面的技术视角和实践指导。 总的来说,本文通过具体案例和技术要点,深入浅出地介绍了分布式锁的实现和安全性问题,对读者了解分布式锁的应用场景、核心原理以及安全性问题具有一定的指导意义。同时,通过对比分析etcd分布式锁和Redis锁的优劣势,为读者提供了全面的技术视角和实践指导。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《etcd 实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(17)

  • 最新
  • 精选
  • jeffery
    老师太厉害了👍etcd和redis 分析的太太透彻了!终于明白了etcd和redis 锁的区别了…….专栏快接近尾声了……真有点不舍!

    作者回复: 赞jeffery一直坚持不懈的学习,感谢认可,专栏虽即将结束,但学习与探索未知领域从未有终点,后面有什么有趣的案例、新的体会,我也会通过专栏、微信公众号、博客等各种渠道与大家一起分享交流!

    2021-03-10
    22
  • 那时刻
    老师文中提到的思考题,多个client抢同一把锁与多个client各自抢自己的锁。我的想法是多个client抢同一把锁,在client数目多的时候,同一把锁的竞争比较激烈。而多个client各自抢各自的锁,会有锁饥饿问题,比如新的client因其version比较小,更容易获得锁。

    作者回复: 赞,我补充一点,多个client通过写同key抢同把锁,主要有惊群效应,同时获取锁性能也低点,毕竟是需要实时写入相关key的,而后者,revision是按时间全局递增的,因此新的client 写入的key revision会比较大,拿锁的顺序可以理解为按时间顺序排队。

    2021-03-10
    7
  • 石小
    唐老师好,etcd有像innodb那样能能控制持久化程度的配置(主要指多久fsync一次磁盘)吗?或者说,etcd可能出现持久化失败(写入磁盘缓存,没fsync)吗?如果持久化失败会有哪些影响?

    作者回复: 有的,etcd提供了如下两个参数可以控制事务提交的行为。 --backend-batch-interval '' BackendBatchInterval is the maximum time before commit the backend transaction. --backend-batch-limit '0' BackendBatchLimit is the maximum operations before commit the backend transaction. 在etcd v3.4.9中,backend-batch-interval如果你没指定,默认是100ms,对应的异步goroutine将批量、每隔100ms,将boltdb事务进行提交。 backend-batch-limit默认是10000,当堆积的put/del等操作若超过10000个,则会同步触发boltdb事务提交 ,若boltdb事务持久化失败,则会异常退出,重启时会重放最新WAL日志中已提交的日志条目,再次执行。

    2021-03-17
    2
    4
  • types
    你要注意的是,实现分布式锁的方案有多种,比如你可以通过 client 是否成功创建一个固定的 key,来判断此 client 是否获得锁,你也可以通过多个 client 创建 prefix 相同,名称不一样的 key,哪个 key 的 revision 最小,最终就是它获得锁。至于谁优谁劣,我作为思考题的一部分,留给大家一起讨论。 1. 按照文中介绍concurrency包中用的是prefix 2. 如果使用相同的key,我能够想到存在的问题,在释放锁后,会导致获取锁的事务同时发生,事务数量变得很大

    作者回复: 嗯,最主要是惊群效应,所有client都会收到相应key被删除消息,都会尝试发起事务,写入key,性能会比较差

    2021-03-11
    4
  • 江山如画
    我最近在做的工作中遇到了分布式锁,这篇文章解决了工作中的很多疑惑,忍不住想要分享给同事们,逻辑合理,切中要害,写的太赞了。

    作者回复: 感谢分享,最近我在极客时间直播中也分享了更多k8s最佳实践案例, 后面也将整理到专栏中。

    2021-09-11
  • @%初%@
    我理解多个客户端写一个key,与多个客户端写多个key,可以理解为非公平锁与公平锁。主要还是要看业务场景处理。

    作者回复: 嗯,性能也要考虑下

    2021-04-13
  • Geek_604077
    死锁、脑裂、惊群效应是分布式锁的核心问题,你知道它们各自是怎么一回事吗?ZooKeeper 和 etcd 是如何应对这些问题的呢? 死锁:加锁后由于没有添加锁的过期时间或者锁的时间设置过长,服务异常crash或者服务执行后漏执行释放锁操作,导致锁长时间没有释放 脑裂:分布式体系结构中的集中式结构(也称为 Master/Slave 架构),一个Master节点多个Slave节点,所有的请求数据处理必须先经过Master中央服务器,由Master统一进行资源和任务调度,中央服务器根据这些信息,将任务下达给节点服务器,节点服务器执行任务,并将结果反馈给中央服务器。脑裂是在某些特殊条件下,如主备切换,Slave在与Master的网络出现故障的时候,Slave会认为Master已经故障,从而成为新的master,而原来的master也没有卸任,从而导致存在两个Master在对外服务,存在多master会导致共享资源的互斥性遭到破坏,出现资源争抢,数据不一致等问题 惊群效应:指多进程(多线程)在同时阻塞等待同一个事件的时候(休眠状态),如果等待的这个事件发生,那么他就会唤醒等待的所有进程(或者线程),但是最终却只能有一个进程(线程)获得这个时间的“控制权”,对该事件进行处理,而其他进程(线程)获取“控制权”失败,只能重新进入休眠状态,这种现象和性能浪费就叫做惊群效应。(当你往一群鸽子中间扔一块食物,虽然最终只有一个鸽子抢到食物,但所有鸽子都会被惊动来争夺,没有抢到食物的鸽子只好回去继续睡觉, 等待下一块食物到来。这样,每扔一块食物,都会惊动所有的鸽子,即为惊群。) etcd如何避免死锁:利用Lease的活性检测机制,它提供了检测各个客户端存活的能力。你的业务 client 需定期向 etcd 服务发送"特殊心跳"汇报健康状态,若你未正常发送心跳,并超过和 etcd 服务约定的最大存活时间后,就会被 etcd 服务移除此 Lease 和其关联的数据。通过 Lease 机制就优雅地解决了 client 出现 crash 故障、client 与 etcd 集群网络出现隔离等各类故障场景下的死锁问题。一旦超过 Lease TTL,它就能自动被释放,确保了其他 client 在 TTL 过期后能正常申请锁,保障了业务的可用性。 etcd如何避免集群脑裂:在leader选举上采用了过半机制,即得到一半以上的follow才能成为leader,且新leader就任后旧leader必须卸任,所以etcd不存在脑裂问题 etcd如何避免惊群效应:mutex,通过 Watch 机制各自监听 prefix 相同,revision 比自己小的 key,因为只有 revision 比自己小的 key 释放锁,才能有机会,获得锁
    2022-02-16
    20
  • Geek_604077
    若你锁设置的 10 秒,如果你的某业务进程抢锁成功后,执行可能会超过 10 秒才成功,在这过程中如何避免锁被自动释放而出现的安全性问题呢? 加锁时,先设置一个过期时间,然后我们开启一个「守护线程」,定时去检测这个锁的失效时间,如果锁快要过期了,操作共享资源还未完成,那么就自动对锁进行「续期」,重新设置过期时间。 幸运的是,已经有一个库把这些工作都封装好了:Redisson。 Redisson 是一个 Java 语言实现的 Redis SDK 客户端,在使用分布式锁时,它就采用了「自动续期」的方案来避免锁过期,这个守护线程我们一般也把它叫做「看门狗」线程。
    2022-02-16
    2
  • Yang
    etcd实现的分布式所能保证高性能不
    2021-12-02
    2
  • 雄哼哼
    redis主备切换过程中,备的数据还没追上的时候 应该是禁止写入的,所以redis的set nx是写不进去的
    2023-04-16归属地:广东
收起评论
显示
设置
留言
17
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部