一、分布式锁的核心概念
分布式锁是一种在分布式系统环境下,用于保证多个进程/节点对共享资源实现互斥访问的机制。其本质是通过某种中间件(如Redis、ZooKeeper等)实现跨节点的锁控制,确保在分布式环境中,同一时刻只有一个客户端能获取锁并执行关键操作,避免出现并发冲突。
二、分布式锁应用场景
场景1:分布式定时任务重复执行
- 业务背景:多个服务器节点部署相同的定时任务(如每日生成报表),需避免重复执行。
- 无分布式锁的问题:
- 节点A和节点B在同一时间触发任务;
- 两个节点同时生成报表,导致数据重复写入或资源浪费。
- 分布式锁的作用:
任务执行前先获取锁,只有获取锁的节点能执行任务,其他节点等待或跳过,避免重复操作。
场景2:微服务接口幂等性保障
- 业务背景:支付接口可能因网络重试导致多次调用,需保证同一笔支付只扣款一次。
- 无分布式锁的问题:
- 用户点击支付后,因网络延迟导致客户端重试;
- 多个支付请求同时到达服务器,可能多次扣除余额。
- 分布式锁的作用:
以订单ID为键获取分布式锁,确保同一订单的支付请求仅能被处理一次,实现幂等性。
三、分布式锁核心特性与需求
分布式锁需满足以下关键特性:
- 互斥性:同一时刻仅一个节点持有锁;
- 安全性:锁只能由持有者释放,避免误释放(如用唯一标识校验);
- 容错性:节点崩溃时锁需自动失效(如超时机制);
- 可用性:中间件集群故障时,锁服务仍能正常工作(如ZooKeeper的选举机制)。
四、分布式锁常见的实现方式
(一)基于关系型数据库(如MySQL)的实现
1. 实现原理
- 唯一索引方案:通过插入唯一索引记录标识锁状态,插入成功即获取锁
- 排他锁方案:使用
SELECT ... FOR UPDATE
语句加行锁
2. 核心问题
问题类型 | 具体表现 |
---|---|
性能瓶颈 | 数据库IO操作耗时高,并发场景下频繁加锁导致吞吐量骤降(TPS通常<1000) |
锁失效缺失 | 无自动过期机制,客户端崩溃会导致锁永久占用,需额外实现定时任务清理死锁 |
可靠性不足 | 主从切换时可能出现锁丢失(如MySQL半同步复制延迟) |
集群复杂 | 需处理数据库连接池管理、事务一致性等问题,实现复杂度高 |
3. 适用场景
- 小规模系统(QPS<100)
- 对性能要求极低的测试环境
- 无高可用需求的简单场景
(二)基于Redis的分布式锁
1. 实现演进
- 基础方案:使用
SET NX key value
加锁,DEL key
释放锁(存在误删风险) - 安全方案:
SET key value NX PX 30000
(加锁时设置唯一标识+过期时间) - Redlock算法(多实例方案):
- 依次向N个Redis实例申请锁
- 超过半数实例成功则认为获取锁
- 释放锁时向所有实例发送释放请求
2. 核心优缺点
- 优势:
- 高性能:单实例TPS可达10万+,适合高并发场景
- 轻量级:纯内存操作,实现简单
- 灵活扩展:支持主从/集群模式
- 风险点:
- 主从切换时可能丢锁(异步复制导致)
- 需严格控制过期时间(过短易误释放,过长导致死锁)
3. Redlock算法实战参数
参数 | 推荐值 | 说明 |
---|---|---|
实例数N | 5 | 保证半数以上节点可用(3节点需2成功,5节点需3成功) |
锁过期时间 | 5-10s | 需大于网络RTT+业务处理时间,建议为业务耗时的1.5倍 |
重试间隔 | 50-100ms | 失败后随机延迟重试,避免惊群效应 |
(三)基于ZooKeeper的分布式锁
1. 实现原理
- 利用ZooKeeper的临时顺序节点特性:
- 客户端在
/locks
路径下创建临时顺序节点 - 检查是否为最小序号节点,是则获取锁
- 非最小节点监听前一节点删除事件
- 释放锁时删除临时节点,触发后续节点获取锁
- 客户端在
2. 核心优势
- 自动失效机制:客户端崩溃时临时节点自动删除,避免死锁
- 强一致性:基于ZAB协议保证分布式事务一致性
- 高可靠性:节点故障时通过选举机制快速恢复
- 可重入性:可通过节点路径记录客户端标识实现重入逻辑
3. 性能表现
- 单次锁操作耗时约10-50ms(含网络往返)
- 集群模式下吞吐量可达5000-10000TPS
- 适合对可靠性要求高于性能的场景