Skip to content

分布式锁与限流

1. 这是什么

Redis 常被用于实现分布式锁和限流。 这类方案不是 Redis 的唯一用法,但在分布式系统里非常高频。

一句话理解:

  • 分布式锁解决“跨节点互斥”
  • 限流解决“超过容量时如何保护系统”

2. 为什么重要

很多跨节点互斥、幂等控制、请求保护场景,都会尝试借助 Redis 完成。 但如果不了解边界条件,很容易写出:

  • 看起来可用
  • 实际不安全

的方案。

3. 先建立直觉:锁和限流不是同一类问题

它们都可能用 Redis 实现,但解决的问题完全不同:

能力主要问题
分布式锁多个节点能不能同时进入临界区
限流超过系统承载能力时,怎么限制入口流量

很多人会把所有并发问题都试图用锁解决,这是非常危险的。

4. 核心内容

4.1 分布式锁的基本模型

Redis 锁最常见的思路是:

  • 用一个 key 表示锁是否被持有
  • SET key value NX PX ttl 原子加锁

其中最关键的点有两个:

  • NX:只有 key 不存在时才设置
  • PX ttl:避免锁永不释放

4.2 为什么释放锁一定要校验归属

这是 Redis 分布式锁最关键的安全点之一。 如果你只是简单:

text
DEL lock:key

就有可能删掉别人加的锁。

所以正确思路通常是:

  • 加锁时写入唯一 token
  • 释放时先比对 token,再删除

4.3 锁超时与续期

锁必须设置过期时间,否则持锁节点挂掉时可能永远不释放。 但过期时间太短又可能导致:

  • 业务还没执行完,锁先过期

这时就会涉及:

  • 续期
  • 看门狗机制

4.4 Redisson 认知

学习阶段不一定要立刻深挖所有实现细节,但要知道:

  • Redisson 这类成熟客户端已经帮你处理了很多分布式锁细节

这也是为什么工程里往往更推荐:

  • 用成熟实现
  • 少手写不完整锁逻辑

4.5 限流的基本实现思路

Redis 限流常见思路包括:

  • 固定窗口
  • 滑动窗口
  • 令牌桶 / 漏桶近似实现

核心目标都是:

  • 在高峰流量来时保护系统容量

5. 学习重点

这一章最重要的是掌握:

  • 分布式锁必须校验锁归属
  • 锁超时和续期都是核心边界条件
  • 锁不是万能方案,适用范围有限
  • 限流本质是容量保护,而不是简单拒绝请求

6. 常见问题

6.1 释放锁时不校验归属

这是最危险的实现错误之一。

6.2 锁过期时间设置不合理

太短会误释放,太长会拖慢恢复。

6.3 把所有并发问题都试图用锁解决

很多问题其实更适合:

  • 限流
  • 幂等
  • 队列削峰

7. 动手验证

这一节我已经在当前 Docker Redis 环境里实际验证过。

7.1 获取锁

bash
docker exec redis-lab redis-cli DEL lock:order
docker exec redis-lab redis-cli SET lock:order token-1 NX PX 30000
docker exec redis-lab redis-cli SET lock:order token-2 NX PX 30000

我实际看到的关键结果是:

text
OK
(第二次获取失败,返回空结果)

这说明:

  • 第一次成功拿锁
  • 第二次因为锁已存在而失败

7.2 安全释放锁

bash
docker exec redis-lab redis-cli EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:order token-2
docker exec redis-lab redis-cli EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:order token-1

我实际验证到的结果是:

text
0
1

这说明:

  • 错误持有者不能释放锁
  • 正确持有者才能删除锁

7.3 限流实验思路

如果你想进一步练习限流,可以从最简单的计数型窗口开始:

bash
docker exec redis-lab redis-cli INCR limit:api:user1
docker exec redis-lab redis-cli EXPIRE limit:api:user1 60

你可以再结合应用层逻辑判断:

  • 超过阈值就拒绝

8. 练习建议

  • 写一个简单的 Redis 锁示例
  • 设计一个秒杀接口限流策略
  • 复盘 Redis 锁可能失效的边界情况
  • 总结“锁适合什么问题,限流适合什么问题”

9. 自测问题

  • 为什么分布式锁要绑定唯一标识?
  • 锁续期是为了解决什么问题?
  • 限流和加锁分别更适合哪类场景?
  • 为什么说 Redis 锁“看起来简单,边界很多”?

10. 自测核对要点

  • Redis 分布式锁的关键是原子加锁和安全释放
  • 锁归属校验是必须条件
  • 续期是为了避免业务未完成时锁提前失效
  • 限流关注的是系统容量保护,不是互斥控制