分布式锁:被互联网大厂用了10年的"老工具",为啥现在还在踩坑?

上周跟一个做电商的朋友在大排档喝冰啤酒,他说上个月618大促第三天,凌晨的订单突然开始跳库存负数,运维团队排查了整整72小时,翻了所有的调用链日志,最后发现就是个没写对的分布式锁。 说真的,干这行快10年了,我见过太多人把分布式锁当银弹。但凡碰到并发冲突,第一反应就是”上Redis锁”,根本不想想自己的场景到底配不配用这个东西。

先把最蠢的坑说在前面

我见过至少三分之一的分布式锁事故,根本不是锁写错了,是压根不该用锁。 举个最常见的例子:用户账户的积分变更。很多团队上来就给积分接口套一层Redis分布式锁,生怕并发的时候积分算错。但你仔细想想,这个场景的冲突本质是”同一个用户的积分同时被两个请求修改”,用数据库的乐观锁加个版本号,成本比你搭一套分布式锁低十倍,可靠性还高得多。 更离谱的是还有人在单节点部署的服务里用分布式锁。相当于你家里就你一个人,你出门的时候还非要给家门上挂三把锁,纯纯脱裤子放屁。
分布式锁常见生产故障根因分布饼图
分布式锁常见生产故障根因分布饼图
剩下三分之二的事故,基本都来自几个固定的原因:锁过期了业务还没执行完,主从切换的时候锁丢了,锁的key没做隔离导致不同业务互相抢锁,甚至还有人把锁的过期时间设成了永久,某个节点宕机了,锁再也没释放,整个业务直接卡死。 上次有个做本地生活的团队找我救火,他们的商家提现接口卡死了整整4个小时,原因就是某个节点在执行提现逻辑的时候触发了OOM,被系统直接杀掉了,但是之前拿的锁因为没有设置过期时间,就一直留在Redis里,后面所有的提现请求都在等这把锁,几百万的提现款卡在系统里动不了。

别把分布式锁当魔法,它的能力边界比你想的窄

很多人对分布式锁的认知,还停留在”只要拿到锁,就绝对不会有并发冲突”的层面。 但实际上,分布式锁从诞生的第一天起,就没有绝对的安全。 说白了,分布式锁的核心逻辑就是:在分布式集群的多个节点之间,找一个所有节点都能共识到的”裁判”,谁先拿到裁判的认证,谁才有资格操作共享资源。 这个裁判选谁,直接决定了锁的可靠性和性能上限。 选数据库当裁判?稳是真的稳,毕竟数据库的事务隔离级别摆在那,只要锁没释放,别的节点绝对拿不到。但慢也是真的慢,大促的时候数据库连接池都快打满了,你还在那抢行锁,这不纯纯给数据库添堵。 选Redis当裁判?快是真的快,单节点每秒能扛十万级别的锁请求,延迟也就亚毫秒级。但脆也是真的脆。Redis的主从复制是异步的,当你在主节点上写了锁,还没同步到从节点的时候,主节点突然挂了,从节点被提升为新的主节点,这把锁就相当于凭空消失了。两个节点同时拿到锁的情况,就这么发生了。
Redis主从切换时分布式锁失效时序图
Redis主从切换时分布式锁失效时序图
之前某头部电商的秒杀系统,就是栽在这个问题上。当时Redis集群主节点发生了一次网络分区,主从同步延迟了大概300毫秒,就在这300毫秒里,两个应用节点同时拿到了同一个商品的库存锁,一秒钟卖出去了三倍于库存的秒杀名额,运营在后台看着库存数字跳成负数,当场人都麻了。 选ZooKeeper或者etcd当裁判?稳是真的稳,毕竟Raft和Zab协议都是强一致的,只要多数节点确认了锁的存在,就不会出现主从切换丢锁的问题。但慢也是真的慢,每次加锁都要走一轮共识流程,延迟大概在几毫秒到几十毫秒不等,性能也就只有Redis的十分之一,扛不住秒杀场景那种每秒几万的并发锁请求。

现在的分布式锁,已经不是大厂的专属玩具了

很多人对分布式锁的印象,还停留在”只有互联网大厂的大促场景才需要用”。 但实际上,现在从创业公司的共享业务,到传统制造业的设备调度,甚至是AI训练集群的任务分配,到处都能看到分布式锁的影子。 整个分布式锁的产业生态,现在基本分成两个阵营。 第一个阵营是Redis生态,大概占了七成左右的存量市场。毕竟大部分公司本来就部署了Redis集群,加个分布式锁的成本几乎为零,再加上Redisson这些开源组件把看门狗、可重入锁这些功能都做全了,大家用着也顺手。哪怕知道Redis锁不是绝对安全,但对于大部分不是金融级的场景来说,这点风险完全可以接受。 第二个阵营是强一致共识生态,也就是etcd、ZooKeeper这些组件,大概占了三成左右的增量市场。尤其是随着K8s生态的普及,etcd已经成了K8s集群的标配,很多云原生的组件直接用etcd做分布式锁,根本不需要额外搭一套Redis。比如K8s的控制器管理器,各个节点之间就是靠etcd的分布式锁来选主,保证同一时间只有一个控制器在处理集群的调度任务。 说实话,我一直觉得很多人吹Redis锁的性能,根本没算过一致性的成本。你为了快那几毫秒,出一次事故的损失,够你把整个集群换成etcd用十年。

别等锁丢了才想起,分布式锁根本没有绝对安全

现在大部分团队的分布式锁使用,根本没有统一的规范。 有人用最原始的setnx命令写锁,有人用Redisson封装的可重入锁,还有人甚至把NFS的文件锁当分布式锁用。出了问题,连日志都查不到,根本不知道是谁拿了锁,什么时候拿的,什么时候放的。 我见过最离谱的一个案例,是某个做共享充电宝的团队,给锁的key没加业务前缀,结果两个完全不相关的业务用了同一个锁key:一个是充电宝的订单状态更新,一个是商户的结算逻辑。结算逻辑因为跑批占了锁两个小时,直接把订单状态更新的流程卡死了,一万多个用户还回去的充电宝,系统显示没还,被扣了几十块的滞留费,投诉电话直接打爆了客服中心。 这种问题的本质,根本不是技术实现的问题,是治理的问题。很多团队把分布式锁当成一个纯技术组件,根本没有配套的监控、告警、审计机制。锁的等待时长是多少,持有时长是多少,有没有出现过期没释放的锁,这些指标从来没人看。等到出了资金损失、用户投诉的时候,才想起要排查锁的问题,早就晚了。

未来3年,分布式锁的进化方向根本不是”更安全”

未来3年,分布式锁的进化方向根本不是
未来3年,分布式锁的进化方向根本不是”更安全”
我跟几个云厂商的架构师聊过,大家对未来3-5年分布式锁的发展判断,其实出奇的一致。 首先,分布式锁的使用会越来越克制。现在很多场景下,大家为了所谓的”并发安全”,上来就上分布式锁,但实际上很多冲突根本不需要锁来解决。比如用CRDT数据结构,用消息队列串行化处理请求,这些方案的成本比分布式锁低得多,可靠性还更高。未来会有越来越多的场景,主动放弃分布式锁,用更轻量的方案解决并发问题。 其次,锁的可观测性会成为标配。现在的分布式锁基本是个黑盒,出了问题根本查不到根因。未来所有的托管锁服务,都会把锁的申请、持有、释放、续期的全链路日志打通,把锁的等待时长、持有时长、过期次数这些指标做成可视化的大盘,一旦出现锁等待超时、锁过期没释放的情况,直接触发告警,根本不用等业务出问题才排查。 最后,锁的抽象层会越来越统一。现在的分布式锁是跟底层存储绑定的,Redis锁只能用Redis,etcd锁只能用etcd,业务代码要适配不同的锁实现,非常麻烦。未来会出现统一的锁抽象接口,不管底层是Redis还是etcd,甚至是数据库,上层业务只需要调用统一的接口就行,根本不用关心底层的实现细节。 说白了,分布式锁从来不是什么高深的技术,它就是个解决问题的工具。工具的好坏,从来不是看你用了多牛的技术栈,是你有没有搞清楚自己到底需不需要这个工具。

作者|fawen

排版|fawen

审核|小北

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:分布式锁:被互联网大厂用了10年的"老工具",为啥现在还在踩坑?
文章链接:https://lfdjt.com/info_23_31191.html