问题
简历中提到业务场景使用了锁,请解释锁的使用方式,在分布式集群环境下为什么单机锁会失效,以及分布式锁的常见实现方式、原理、优缺点和选择策略?
考察点
- 理解单机锁(如synchronized和Lock)的原理和局限性,特别是JVM级实现如何导致分布式失效。
- 掌握分布式锁的三种主流实现(数据库、Redis、ZooKeeper),包括核心机制(如唯一约束、SET NX、临时顺序节点)。
- 分析优缺点,涉及性能、一致性(CAP理论)、可靠性(如锁丢失、死锁防范)。
- 展示场景选择能力,从并发量、组件引入、可靠性需求等角度评估。
- 反映从面经中学到的深度,如Redlock防丢失、看门狗续期、ZK公平锁。
解释
在面试中,回答应结构化:先确认简历内容并解释单机锁失效,然后分方式介绍分布式锁(用表格对比),融入代码示例和原理细节,最后总结选择逻辑。控制2-3分钟,展示深度如Lua原子性和ZAB协议。
单机锁在分布式失效:简历中锁多用于业务同步,如synchronized加方法确保互斥。但集群多实例下失效,因synchronized基于对象头Mark Word(JVM内存),Lock如ReentrantLock是堆对象,各JVM独立,无法跨机协调。业务需分布式锁实现全局互斥。
分布式锁实现:
- 数据库:用InnoDB行锁/唯一索引实现悲观锁。
- 原理:INSERT唯一记录获锁(ON DUPLICATE失败),或SELECT FOR UPDATE锁行;定时清理超时锁。
- 示例:
INSERT INTO locks (lock_key, expire_time) VALUES ('order_lock', NOW() + INTERVAL 30 SECOND); - 优缺点:简单、可靠(ACID保证一致/持久),但IO高、性能低(高并发瓶颈)。
- Redis(Redlock):基于单线程原子命令。
- 原理:SET key value NX PX ttl(NX不存在设,PX毫秒过期);释放用Lua脚本校验value再DEL。可重入用Hash计数,看门狗后台续期(Redisson实现)。
- 示例:
SET lock_key uuid NX EX 30;Lua:if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) end - 优缺点:性能极高(10万QPS),但AP模型易丢锁(复制延迟),用Redlock(多节点多数派)缓解。
- ZooKeeper:用临时顺序节点实现。
- 原理:创建/locks/lock-[seq],最小seq获锁;监听前节点删除获通知,支持公平等待。关闭连接自动释锁。
- 示例(Curator):
mutex.acquire(); ... mutex.release(); - 优缺点:强一致(CP,ZAB协议无丢锁),但性能中(写慢),组件复杂少用。
| 方式 | 原理 | 优点 | 缺点 | 场景 |
|---|---|---|---|---|
| 数据库 | 唯一/FOR UPDATE | 可靠、简单 | 性能低 | 并发低、无新组件 |
| Redis | SET NX + Lua | 高性能、丰富功能 | 可能丢锁 | 高并发、性能优先 |
| ZK | 顺序节点 + 监听 | 一致性强、公平 | 复杂、性能中 | 中并发、强一致 |
总结:单机锁限JVM,分布式选数据库(稳)、Redis(快,用Redlock)、ZK(一致)。依据并发(高选Redis)、可靠性(高选数据库/ZK)。
相关扩展知识
- 单机锁升级:synchronized偏向/轻量/重量锁,AQS支持Lock自定义。
- 风险优化:死锁加超时/心跳;粒度细化减争用;乐观锁(版本)替悲观。
- CAP:数据库/ZK CP,Redis AP+Redlock近CP。
- 面经点:Redlock N/2+1节点设锁防脑裂;看门狗每ttl/3续期。
- 替代:MQ异步、CAS乐观。
扩展问题
- Redis锁丢失怎么防:用Redlock多节点多数成功;加fence token(版本)防旧锁执行。
- 数据库锁性能优化:用读写分离、主从;锁表分细粒;结合缓存减DB压力。
- ZK vs Redis公平锁:ZK顺序天然公平,Redis默认非公平(Redisson可公平,但开销大)。