架构师必备:分布式锁方案选型
当同时操作共享资源时需要做并发控制。在单机上用synchronized或ReentrantLock能解决的互斥问题到了多机部署的分布式环境就行不通了因为它们只在单个JVM进程内生效跨多机就需要分布式锁了。先说结论最常用的分布式锁方案是Redis锁、DB乐观锁、或DB逻辑锁。高并发、能容忍极端情况下短暂的弱一致选Redis锁并发不高、强一致要求高选DB乐观锁、或DB逻辑锁不推荐DB行锁、ZK锁。下面展开介绍。一把合格的分布式锁要满足什么先对齐一下标准后续每种方案的好坏都可以对照互斥最基本的要求任意时刻只能有一个客户端持有同一把锁防死锁持有锁的客户端如果宕机了锁能自动释放防止其它客户端永远加锁失败可重入同一个客户端在持锁期间能再次拿到这把锁避免自己阻塞自己性能加锁、解锁开销要小吞吐要高悲观锁和乐观锁悲观锁觉得并发冲突大概率会发生所以操作前先加锁把资源独占起来操作完再释放。典型实现DB行锁select ... for update、DB逻辑锁通过新增lock_status状态字段实现、Redis的set nx px命令优点严格互斥不用像乐观锁那样反复重试缺点持锁期间其它线程只能等、有死锁风险、吞吐被锁的粒度和持有时间卡住适用场景适合写冲突频繁的场景乐观锁觉得冲突很少所以一开始不加锁等更新时再判断中途是否被其它线程修改了。典型实现version字段、CAS先比较再修改优点无锁实现开销较低缺点并发冲突较多时需要不断重试可能有ABA问题但用递增的version能解决仅CAS比较值则不行适用场景适合读多写少的场景如果写并发很高但误用了乐观锁的话会导致线程不停地重试最终线程池耗尽的严重问题两个并发更新请求的时序图如下上图展示了乐观锁的流程业务入口服务本身无存储、数据都在下游存储服务上查询时一并拿到业务数据、系统version回写时带上这个version做校验。这样能解决一个典型问题两个并发请求因网络抖动乱序到达存储服务先到的请求反而后处理导致旧数据覆盖新数据。有了乐观锁校验version不匹配的更新会失败从而避免旧覆盖新。主流方案选型1. DB行锁不推荐原理 借助InnoDB的排他锁在事务里执行select ... for update对查到的行加行锁事务提交或回滚后释放。别的事务再尝试上DB行锁时会阻塞住。实现细节必须在数据库事务里用否则for update一执行完就释放了起不到持锁的作用where条件必须命中主键或唯一索引否则会锁表、或者产生大段间隙锁数据库事务内不要做耗时操作比如调外部RPC接口设置合理的锁等待超时innodb_lock_wait_timeout别让被阻塞的请求一直干等最佳场景低并发、强一致、已有DB不想引入新中间件 比如公司内部系统的定时任务多个实例都可能触发该定时任务需要保证同一时间只有一个实例在跑。2. DB乐观锁原理 不靠数据库自带的行锁而是在已有业务表里新增一个version字段依靠版本号、乐观锁来实现。实现细节先查询得到版本号v1然后更新时再判断version是否为版本号v1即update ... where biz_id? and version?最后判断影响行数如果大于0则说明修改成功如果是0则说明中途被别的线程修改了需要重试-- 通用更新带上version条件影响行数为0则说明被并发修改需重试 UPDATE biz_record SET name #{name}, status #{status}, version version 1 WHERE biz_id #{bizId} AND version #{version};对应的Java示例// 业务代码查询版本号 - 带version更新 - 判断影响行数失败则重试 public boolean updateBiz(String bizId, String name, int status) { int maxRetry 3; for (int i 0; i maxRetry; i) { // 1. 先查询得到版本号v1 Biz biz bizMapper.selectByBizId(bizId); // 2. 更新时带上version条件即 where biz_id? and versionv1 int affected bizMapper.updateByBizId(bizId, name, status, biz.getVersion()); // 3. 影响行数大于0说明成功为0说明被别的线程改过version变了重试 if (affected 0) { return true; } } throw new BizException(并发冲突更新失败); }最佳场景中等并发、读多写少、能接受DB的性能上限 比如库存扣减、余额扣减、业务状态流转并发冲突不算特别频繁乐观锁足够。又比如核心链路上减少不必要的外部依赖不用Redis锁、只用DB乐观锁毕竟DB的稳定性要高于Redis。3. DB逻辑锁原理 不靠数据库自带的行锁而是在业务表里新增lock_status状态字段用一条带条件的UPDATE抢占锁抢到就置为占用状态释放再置回空闲状态。靠DB写操作的行级一致性保证同一时刻只有一个客户端抢成功是悲观锁。实现细节加锁update ... set lock_status1 where biz_id? and (lock_status0 or lock_expire_atnow())影响行数大于0即加锁成功解锁时带上lock_owner校验防止误删其它线程上的锁防死锁持有者宕机没正常释放状态会一直占用所以要加lock_expire_at过期时间靠定时任务清理过期锁、或持有者续期-- 加锁状态空闲、或已过期才能抢到同时记下持有者和过期时间 UPDATE biz_record SET lock_status 1, lock_owner #{owner}, lock_expire_at #{expireAt} WHERE biz_id #{bizId} AND (lock_status 0 OR lock_expire_at NOW()); -- 解锁带上 lock_owner 校验防止误删别人的锁 UPDATE biz_record SET lock_status 0, lock_owner NULL, lock_expire_at NULL WHERE biz_id #{bizId} AND lock_owner #{owner}; -- 兜底定时任务清理持有者宕机导致的过期锁 UPDATE biz_record SET lock_status 0, lock_owner NULL WHERE lock_status 1 AND lock_expire_at NOW();对应的Java示例// 加锁影响行数大于0即成功 public boolean tryLock(String bizId, String owner, long leaseMs) { Date expireAt new Date(System.currentTimeMillis() leaseMs); return bizMapper.acquireLock(bizId, owner, expireAt) 0; } // 释放锁带上 owner 校验影响行数大于0即释放成功 public boolean unlock(String bizId, String owner) { return bizMapper.releaseLock(bizId, owner) 0; }最佳场景中等并发、需要持久化锁状态 比如跨多个服务、多个步骤的长流程需要持锁一段时间、且锁状态要落库重启不丢、可审计追溯。DB逻辑锁持锁不绑事务、状态可持久化比DB行锁灵活。4. Redis锁单节点redis锁原理 依靠Redis单线程串行执行的特点用SET key value NX PX timeout一条命令原子完成“键不存在才设置 设置过期时间”。设置成功就算拿到锁过期时间一到自动释放、防死锁。实现细节value必须是唯一标识比如UUID释放锁时先比对再删防止误删其它线程上的锁释放锁需要保证原子性比对value、与删除是两步要用lua脚本包成原子操作锁续期业务执行时长不可控过期时间设短了业务没跑完锁就释放了设长了宕机后锁仍然占用。Redisson用看门狗机制解决后台线程每隔一段时间自动检查、并续期锁的TTL直到业务跑完、并主动释放锁可重入用Hash结构记下持有者和重入次数同一客户端就能多次获取举例手写Redis锁// 加锁NX保证互斥PX设置过期时间value用唯一标识防误删 public boolean tryLock(String lockKey, String requestId, long expireMs) { return OK.equals(jedis.set(lockKey, requestId, NX, PX, expireMs)); } // 解锁用lua脚本保证“比对删除”的原子性 public boolean unlock(String lockKey, String requestId) { String lua if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end; return jedis.eval(lua, Collections.singletonList(lockKey), Collections.singletonList(requestId)).equals(1L); }生产环境考虑直接用Redisson框架可重入、锁自动续期、lua脚本都封装好了RLock lock redisson.getLock(distributedLock: bizId); try { // 尝试加锁最多等待10s锁自动续期 if (lock.tryLock(10, TimeUnit.SECONDS)) { doBusiness(); } } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } }最佳场景高并发写场景、能容忍极端情况下短暂的弱一致 比如秒杀场景防重复提交、消息消费的幂等处理。并发大要求加锁解锁快能接受Redis主从切换那一瞬间极小概率的锁失效必须要做兜底的业务幂等校验。多节点RedLock锁不推荐Redis的高可用是靠主从异步复制来实现的。有个经典问题客户端A在master加锁成功锁还未同步到slave此时master宕机了slave升成新master客户端B加锁也能成功。于是A、B同时持锁产生并发冲突。针对这个Redis作者提出了RedLock向n个一般5个互相独立的Redis节点申请锁多数n/21成功才算加锁成功少数节点挂了不影响。 但这个方案引入了复杂度、牺牲了性能在GC暂停或网络延迟下仍然有边界问题就不推荐了。单节点Redis锁配合业务幂等兜底已经能解决核心问题了兼顾了性能和正确性。5. ZK锁不推荐原理 靠ZK的临时顺序节点。客户端在/lock路径下创建一个临时顺序节点/lock/seq-00000001然后取出/lock下所有子节点排个序看自己是不是序号最小的是最小的拿到锁不是最小的就监听前一个节点的删除事件前一个节点一删自己被唤醒再判断一次释放锁就是删掉自己创建的节点。客户端宕机导致session失效ZK会自动删掉它建的临时节点锁跟着释放。最佳场景对一致性要求极高、能接受性能和运维代价 比如集群选主节点宁可慢也不能错。在业务场景中就不用考虑了更适合用于集群运维场景比如Hadoop、Kafka那套大数据生态。总结方案一致性性能实现复杂度防死锁最适合的场景DB行锁悲观锁不推荐强一致低低需配置超时低并发强一致、已有 DB内部系统的定时任务DB乐观锁乐观锁强一致中高低无死锁中等并发、读多写少库存扣减、余额扣减、业务状态流转等DB逻辑锁悲观锁强一致中中靠过期兜底中等并发、需持久化锁状态Redis锁悲观锁弱一致高中靠过期续期高并发写场景、可容忍极端弱一致秒杀、幂等ZK锁不推荐强一致低高自动释放集群选主不要在业务场景使用对照上面的表格就能快速找到合适的方案。优先考虑DB乐观锁、DB逻辑锁、Redis锁不推荐DB行锁、ZK锁。

相关新闻

物联网设备电源管理:NBM7100A芯片与低功耗优化实践

物联网设备电源管理:NBM7100A芯片与低功耗优化实践

1. 项目背景与核心挑战在物联网终端设备和便携式医疗设备领域,不可充电的初级电池(如锂亚硫酰氯电池、CR2032纽扣电池)因其高能量密度和超长保存寿命(可达10年以上)成为首选电源方案。但这类电池存在一个鲜为人知的致命…

2026/7/28 14:38:17 阅读更多 →
如何用MemcardRex终极PS1记忆卡编辑器解决存档管理难题

如何用MemcardRex终极PS1记忆卡编辑器解决存档管理难题

如何用MemcardRex终极PS1记忆卡编辑器解决存档管理难题 【免费下载链接】memcardrex Advanced PlayStation 1 Memory Card editor 项目地址: https://gitcode.com/gh_mirrors/me/memcardrex 还在为PS1游戏存档无法跨平台使用而烦恼吗?MemcardRex作为一款专业…

2026/7/28 14:38:17 阅读更多 →
涨薪技术|使用Dockerfile创建镜像

涨薪技术|使用Dockerfile创建镜像

上次的推文内容中介绍了如何使用docker commit的方法来构建镜像,相反推荐使用被称为Dockerfile的定义文件和docker build命令来构建镜像。Dockerfile使用基本的基于DSL语法的指令来构建一个Docker镜像,之后使用docker build命令基于该Dockerfile中的指令…

2026/7/28 14:38:17 阅读更多 →

最新新闻

2026出海服务商深度横评:四类全球化服务商,按企业发展阶段精准选型

2026出海服务商深度横评:四类全球化服务商,按企业发展阶段精准选型

2026年全球出海赛道分化加剧,企业出海不再只有“投流卖货”单一路径。大量实体工厂、跨境品牌、集团企业在全球化布局中陷入两难:只做营销投放,海外分厂、跨国团队管理失控;只做内部管理,线上流量、海外品牌声量长期停…

2026/7/28 14:48:20 阅读更多 →
随机地图算法(优化地牢算法)

随机地图算法(优化地牢算法)

1.前言 如果在阅读此篇文章的时候,不了解地牢算法的建议去看一下,这里不介绍地牢算法了,只是谈论一下地牢算法不好的地方,如何去扩展和优化地牢算法,下面是地牢算法的链接:https://www.cnblogs.com/sufferi…

2026/7/28 14:48:20 阅读更多 →
异构无人机配送系统多目标优化算法解析与实践

异构无人机配送系统多目标优化算法解析与实践

1. 项目概述:异构无人机配送问题的研究背景与挑战 2024年发表在ESWA(Expert Systems With Applications)SCI一区TOP期刊的这篇论文,针对的是当前物流配送领域的一个前沿课题——异构无人机配送系统的多目标优化问题。随着无人机技…

2026/7/28 14:48:20 阅读更多 →
NBUT-2019-ICPC训练赛

NBUT-2019-ICPC训练赛

只写了几道能写的题,菜是原罪 A Mental rotation is a difficult thing to master. Mental rotation is the ability to imagine in your mind how an object would look like from a viewer’s side if you were to rotate it in a particular direction. It is so…

2026/7/28 14:48:20 阅读更多 →
Livewire 3构建高效Quiz系统的实战指南

Livewire 3构建高效Quiz系统的实战指南

1. 为什么选择Livewire 3构建Quiz系统? 去年接手一个在线教育项目时,我需要在两周内交付一个能支持千人并发的随堂测试模块。当时评估了三种方案:传统PHP表单提交、Vue前后端分离架构,以及当时刚发布不久的Livewire 3。最终选择Li…

2026/7/28 14:48:20 阅读更多 →
QQ聊天记录本地数据库解密:逆向工程与数据恢复实战指南

QQ聊天记录本地数据库解密:逆向工程与数据恢复实战指南

1. 项目概述:从数据安全视角看QQ聊天记录解密最近在数据安全与取证分析的圈子里,关于即时通讯应用本地数据解密的话题热度一直不减。特别是像QQ这样拥有海量用户、数据格式又历经多次变更的“老牌”应用,其本地数据库的解密需求,常…

2026/7/28 14:47:20 阅读更多 →

日新闻

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否也曾为官方Om…

2026/7/28 0:00:43 阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

做 RAG 的人应该都踩过这个致命的坑:把几百页的财报、法规、技术手册扔给向量库,问一个具体问题,搜出来的全是沾边但没用的内容 —— 关键信息要么被硬切块拆碎了,要么藏在几十条结果的最下面。语义相似≠真正相关,这个…

2026/7/28 0:00:43 阅读更多 →
抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

2026年做短视频运营,从抖音上扒文案早就不是偷偷抄笔记的事了。我刚开始做内容的时候,每天刷半小时抖音,手动把爆款视频的口播敲进备忘录,一条2分钟的视频得花十来分钟,碰到语速快的还要反复回听。后来试了一圈工具&am…

2026/7/28 0:00:43 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/28 12:04:22 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/28 8:29:16 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/28 5:03:42 阅读更多 →

月新闻