Redis分布式锁争用与微服务并发粒度调优 - 第1节

1. 分布式锁基础:为什么需要分布式锁

1.1 从单体到分布式:锁的演进

在单体应用中,我们使用 synchronized 或 ReentrantLock 即可保证共享资源的互斥访问。但在微服务架构下,多个服务实例运行在不同的 JVM 进程甚至不同的物理节点上,传统的本地锁无法跨进程生效。

核心矛盾: 分布式环境下,多个节点需要像单机一样对共享资源进行互斥访问,但本地锁的作用域仅限于单个进程。

以下场景必须引入分布式锁:

  • 库存扣减: 多个服务实例同时扣减同一商品库存,导致超卖。
  • 定时任务调度: 集群中多个节点执行同一定时任务,只需一个节点执行。
  • 幂等性控制: 防止重复支付、重复下单等操作。
  • 资源隔离: 限制对数据库、文件系统等共享资源的并发访问。
分布式锁典型应用场景 服务实例 A 库存扣减 服务实例 B 库存扣减 服务实例 C 库存扣减 分布式锁协调层(Redis / ZooKeeper / 数据库) 共享资源(库存 / 订单 / 文件)

1.2 分布式锁的核心要求

一个合格的分布式锁必须满足以下特性:

特性 说明 重要性
互斥性 任意时刻只有一个客户端持有锁 必须
死锁预防 持有锁的客户端崩溃后,锁能自动释放 必须
容错性 锁服务自身具备高可用,少数节点宕机不影响 高
可重入性 同一客户端可重复获取同一把锁 按需
公平性 按请求顺序分配锁(非必须) 低
设计要点: 互斥性和死锁预防是分布式锁的底线要求。如果这两条无法保证,锁机制将失去意义。

2. 分布式锁的常见实现方式对比

2.1 基于数据库的实现

利用数据库的唯一索引或行锁实现互斥:

-- 加锁:插入一条唯一记录
INSERT INTO distributed_lock (lock_key, owner, expire_time)
VALUES ('order_123', 'instance_A', '2024-01-01 12:00:00');

-- 解锁:删除记录
DELETE FROM distributed_lock
WHERE lock_key = 'order_123' AND owner = 'instance_A';

优点: 实现简单,不依赖额外中间件。

缺点:

  • 性能瓶颈:数据库 IO 开销大,高并发下容易成为热点。
  • 死锁风险:客户端崩溃后记录无法自动清理,需额外兜底任务。
  • 单点问题:数据库主从切换可能导致锁丢失。

2.2 基于 ZooKeeper 的实现

利用 ZooKeeper 的临时顺序节点和 Watcher 机制实现锁:

// 伪代码:ZooKeeper 分布式锁
1. 在 /locks/order_123 下创建临时顺序节点
2. 获取 /locks/order_123 下的所有子节点
3. 判断自己是否为最小序号节点
   - 是:获得锁
   - 否:监听前一个节点的删除事件,阻塞等待

优点:

  • 强一致性:ZooKeeper 的 ZAB 协议保证数据一致性。
  • 自动释放:临时节点在客户端断开后自动删除,避免死锁。
  • 公平锁:顺序节点天然支持 FIFO 排队。

缺点:

  • 性能较低:每次锁操作需多次网络往返和磁盘写入。
  • 羊群效应:大量客户端同时监听同一节点时,惊群问题严重。
  • 运维复杂:ZooKeeper 集群维护成本较高。

2.3 基于 Redis 的实现

利用 Redis 的 SET NX EX 原子命令实现锁:

// 加锁(原子操作)
SET lock_key unique_value NX EX 30

// 解锁(Lua 脚本保证原子性)
if redis.call("GET", KEYS[1]) == ARGV[1] then
    return redis.call("DEL", KEYS[1])
else
    return 0
end

优点:

  • 高性能:纯内存操作,单机 QPS 可达 10 万+。
  • 简单易用:API 简洁,学习成本低。
  • 丰富的生态:Redisson、Jedis 等客户端提供成熟实现。

缺点:

  • 一致性较弱:Redis 主从异步复制可能导致锁丢失。
  • 需额外处理:锁超时、可重入、续期等逻辑需自行实现。
三种分布式锁实现方式对比 基于数据库 唯一索引 / 行锁 性能:低(磁盘 IO) 一致性:强(ACID) 死锁预防:需额外兜底 基于 ZooKeeper 临时顺序节点 + Watcher 性能:中(磁盘 + 网络) 一致性:强(ZAB) 死锁预防:自动释放 基于 Redis SET NX EX / RedLock 性能:高(纯内存) 一致性:弱(异步复制) 死锁预防:超时自动释放 综合对比 维度 数据库 ZooKeeper Redis 吞吐量 低 中 高 一致性 强 强 弱 运维成本 低 高 低

2.4 三种实现方式总结

对比维度 数据库 ZooKeeper Redis
性能 低(磁盘 IO) 中(ZAB 协议开销) 高(纯内存)
一致性 强(ACID) 强(ZAB) 弱(异步复制)
死锁预防 需额外兜底 自动释放 超时自动释放
运维复杂度 低 高 低
适用场景 低并发、对一致性要求极高 对一致性要求极高、可接受较低吞吐 高并发、可接受弱一致性
选型建议: 在微服务架构中,Redis 分布式锁是主流选择。它兼顾了高性能和可接受的可靠性,配合 RedLock 算法或 Redisson 框架,可以满足绝大多数业务场景。ZooKeeper 更适合对一致性有强诉求的金融、交易类场景。数据库锁仅建议在低并发或作为兜底方案时使用。

2.5 为什么本课程选择 Redis

本课程后续章节将深入 Redis 分布式锁的实战调优,原因如下:

  • 性能优势: Redis 单机 QPS 可达 10 万+,是 ZooKeeper 的 10 倍以上。
  • 生态成熟: Redisson 提供了开箱即用的可重入锁、公平锁、读写锁、红锁等。
  • 微服务亲和: Redis 作为缓存基础设施已广泛部署,引入分布式锁几乎零额外成本。
  • 挑战性: Redis 的弱一致性带来了锁丢失、锁超时、锁续期等经典问题,正是调优的价值所在。