跳转到内容
主菜单
主菜单
移至侧栏
隐藏
导航
首页
最近更改
随机页面
MediaWiki帮助
代码酷
搜索
搜索
中文(中国大陆)
外观
创建账号
登录
个人工具
创建账号
登录
未登录编辑者的页面
了解详情
贡献
讨论
编辑“︁
分布式锁
”︁
页面
讨论
大陆简体
阅读
编辑
编辑源代码
查看历史
工具
工具
移至侧栏
隐藏
操作
阅读
编辑
编辑源代码
查看历史
常规
链入页面
相关更改
特殊页面
页面信息
外观
移至侧栏
隐藏
您的更改会在有权核准的用户核准后向读者展示。
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
= 分布式锁 = == 介绍 == '''分布式锁'''是一种在分布式系统中协调多个进程或服务对共享资源进行互斥访问的机制。在单机环境中,可以使用线程锁(如Java的`synchronized`或`ReentrantLock`)实现同步,但在分布式环境下,由于进程分布在不同的物理节点上,需要一种跨节点的锁机制来保证数据一致性。 分布式锁的核心特性包括: * '''互斥性''':同一时刻只有一个客户端能持有锁。 * '''可重入性''':同一个客户端可以多次获取同一把锁。 * '''锁超时''':避免死锁,锁需支持自动释放。 * '''高可用''':锁服务需具备容错能力,即使部分节点故障仍能工作。 == 实现方式 == === 基于数据库 === 通过数据库的唯一索引或乐观锁实现,例如创建一张锁表: <syntaxhighlight lang="sql"> CREATE TABLE distributed_lock ( lock_name VARCHAR(64) PRIMARY KEY, owner_id VARCHAR(255), expire_time TIMESTAMP ); </syntaxhighlight> 获取锁时执行: <syntaxhighlight lang="sql"> INSERT INTO distributed_lock VALUES ('order_lock', 'client1', NOW() + INTERVAL 30 SECOND); -- 失败则说明锁已被占用 </syntaxhighlight> '''缺点''':数据库性能瓶颈,不具备自动过期能力。 === 基于Redis === 使用Redis的`SETNX`(SET if Not eXists)命令: <syntaxhighlight lang="python"> import redis r = redis.Redis() # 获取锁(设置过期时间防止死锁) lock_acquired = r.set("order_lock", "client1", nx=True, ex=30) if lock_acquired: try: # 执行业务逻辑 finally: r.delete("order_lock") # 释放锁 </syntaxhighlight> '''关键点''': * 必须设置过期时间(`ex`参数) * 释放锁时需验证持有者(防止误删其他客户端的锁) === 基于ZooKeeper === 利用ZooKeeper的临时有序节点: <mermaid> sequenceDiagram Client->>ZooKeeper: 创建临时节点/lock/order-0001 ZooKeeper-->>Client: 节点创建成功 Client->>ZooKeeper: 检查自己是否是最小序号节点 ZooKeeper-->>Client: 确认是最小节点(获得锁) Client->>ZooKeeper: 业务完成后删除节点 </mermaid> Java示例(使用Curator框架): <syntaxhighlight lang="java"> InterProcessMutex lock = new InterProcessMutex(client, "/order_lock"); if (lock.acquire(30, TimeUnit.SECONDS)) { try { // 访问共享资源 } finally { lock.release(); } } </syntaxhighlight> == 算法原理 == === RedLock算法 === Redis官方推荐的分布式锁算法,需在多个独立Redis实例上获取锁: <math> N = 2F + 1 </math> 其中N是总节点数,F是允许的故障节点数。客户端需要在多数节点(>N/2)上获得锁才算成功。 实现步骤: 1. 获取当前时间T1 2. 依次向N个Redis实例请求锁 3. 计算获取锁耗时T2-T1,如果小于锁超时时间且成功获取多数锁,则成功 4. 实际锁有效时间 = 初始设置时间 - (T2-T1) == 实际案例 == === 电商库存扣减 === 场景:秒杀活动中防止超卖 1. 用户下单时尝试获取商品ID对应的分布式锁 2. 查询库存并扣减 3. 释放锁 === 分布式任务调度 === 场景:确保定时任务只在集群中的一个节点执行 1. 任务触发时各节点竞争锁 2. 获得锁的节点执行任务 3. 其他节点跳过执行 == 常见问题 == * '''时钟漂移问题''':不同机器时钟不一致可能导致锁过早失效。解决方案:使用NTP同步时钟,或采用无需绝对时间的算法(如ZooKeeper版本号) * '''长时间阻塞''':持有锁的客户端崩溃可能导致资源长时间不可用。解决方案:设置合理的超时时间,实现锁续约机制(如Redisson的WatchDog) * '''脑裂问题''':网络分区导致多个客户端同时持有锁。解决方案:使用多数派算法(如RedLock) == 进阶优化 == * '''锁分段''':将单个热点锁拆分为多个子锁(如ConcurrentHashMap的分段锁思想),提高并发度 * '''读写锁''':区分读锁(共享)和写锁(排他),适用于读多写少场景 * '''乐观锁''':通过版本号或CAS机制实现无锁编程,如: <syntaxhighlight lang="sql"> UPDATE inventory SET stock = stock - 1 WHERE item_id = 100 AND stock >= 1; -- 检查affected_rows是否大于0 </syntaxhighlight> == 总结 == 分布式锁是分布式系统的基础组件,选择实现方案时需要权衡: {| class="wikitable" |- ! 方案 !! 优点 !! 缺点 |- | '''数据库''' || 实现简单,无需额外组件 || 性能差,无故障转移 |- | '''Redis''' || 高性能,支持丰富特性 || 需处理复杂边界条件 |- | '''ZooKeeper''' || 可靠性高,原生支持临时节点 || 性能较低,依赖ZK集群 |} 实际开发中推荐使用成熟的开源实现(如Redisson、Curator)而非自行造轮子,以规避潜在的分布式系统陷阱。 [[Category:计算机科学]] [[Category:面试技巧]] [[Category:系统设计]]
摘要:
请注意,所有对代码酷的贡献均被视为依照知识共享署名-非商业性使用-相同方式共享发表(详情请见
代码酷:著作权
)。如果您不希望您的文字作品被随意编辑和分发传播,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)