一句话定义:分布式锁(Distributed Lock)是一把挂在"所有机器都看得见的地方"的钥匙,多个 worker 抢同一把锁,同一时刻只有一个能拿到,谁拿到谁干活。
为什么需要它
单机时代,一个进程里的多个线程抢同一份资源,用线程锁(thread lock)就够了。但服务一旦多副本部署——比如 Kubernetes 里起了 5 个 pod,每个 pod 都挂着"每小时刷新一次向量索引"的定时任务——线程锁立刻失效:5 个进程各锁各的,同一件事被跑了 5 遍。
打个比方:公司只有一间会议室,钥匙挂在门口墙上的钩子上,谁拿到钥匙谁进去开会,其他人只能等或先干别的。这个钩子必须放在大家都看得到、且只有一把钥匙的地方,通常由 Redis、ZooKeeper、etcd 或数据库的唯一索引来扮演。
一把靠谱的锁要满足什么
- 加锁原子:判断"还没人持有"和"我持有了"要一步完成,否则两个 worker 会同时以为自己抢到。常见写法是 Redis 的
SET key value NX PX <毫秒>。 - value 写下自己的身份:解锁前先确认锁是不是自己加的,避免超时后误删别人的锁;校验和删除要合成一个原子操作。
- 能自动过期:持锁者崩溃时锁不能永远不释放;任务跑得比过期时间长,还得有个"看门狗"(watchdog)定期续期。
- 抢不到有策略:自旋重试、排队,或直接跳过这一轮。很多 AI 定时任务选跳过,因为下一轮还会来。
和相邻概念的区别
| 概念 | 管住谁 | 解决的问题 |
|---|---|---|
| 线程锁 | 同一进程内的线程 | 内存里的共享变量竞争 |
| 分布式锁 | 跨机器的多个进程 | 同一件事被多个副本重复做 |
| 幂等(idempotency) | 单个执行者 | 重复执行也不产生副作用 |
| 任务队列 | 任务分发 | 一个任务只发给一个 worker |
队列是"发之前就决定给谁",锁是"谁都想干,抢到才算",幂等则是兜底:锁失效、任务跑了两遍,结果也不会错。三者常一起用,但不能互相替代。
对从业者的意义
AI 系统里的典型场景:多副本部署的定时增量索引、同一份文档被多个请求同时触发重建向量、模型权重下载到共享存储、缓存预热、爬虫抓同一个站点。重复跑的代价不只是"慢一点",而是写坏数据、翻倍烧算力,甚至把下游打挂。
两点提醒:锁服务本身要可靠,它挂了锁就形同虚设,不同存储的一致性保证不同,选型以官方文档为准;网络分区和 GC 停顿都可能让持锁者"以为自己还拿着钥匙",所以最关键的操作最好再叠一层幂等或版本号(CAS)做保险。锁的粒度也尽量小,锁"用户 123 的索引"而不是"整个索引任务"。
