☰
Redis 的原理和使用(8)
2026/10/23 2:52:44 网站建设 项目流程

八、分布式锁

分布式环境下多个进程需要互斥访问共享资源,Redis 的原子特性可以充当锁的载体。

一个可用的分布式锁需要逐步补齐几个环节。

8.1 基础实现

利用 SETNX“仅当键不存在时写入”的特性,加锁成功表示获得锁,用完删除键释放锁:

# 加锁 SETNX lock:order 1 # 业务处理 # 释放锁 DEL lock:order

这个版本存在两个隐患:客户端崩溃会导致锁迟迟无法释放;不同客户端可能误删别人的锁。

购票系统的场景可以直观体现锁的价值——多个线程同时抢票,锁保证同一时刻只有一个线程能扣减库存:

8.2 引入过期时间

给锁设置过期时间,客户端崩溃后锁到期自动释放,避免死锁。

setnx 与 expire 分两步执行存在原子性问题,应使用带参数的 SET 一步完成:

# NX:键不存在才写入;EX:过期时间(秒) SET lock:order 1 EX 10 NX

8.3 校验客户端标识

过期时间仍可能提前失效,或旧锁被新客户端接管的瞬间,旧客户端执行 DEL 会误删别人的锁。解法是在 value 中存放客户端唯一标识,删除前先校验是不是自己的锁:

SET lock:order 客户端A的ID EX 10 NX # 释放前先确认 value 是自己的

8.4 Lua 原子解锁

“先 GET 校验再 DEL”两步之间仍有间隙,需要用 Lua 脚本把校验与删除合并成一次原子操作:

if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end

8.5 看门狗续期

过期时间设短了,任务没跑完锁就没了;设长了,持有锁的服务器宕机后其他服务器迟迟拿不到锁。与其固定时长,不如动态续期:看门狗是加锁服务器上的一个独立线程(注意是业务服务器而不是 Redis 服务器),定期检查任务是否仍在执行,为未过期的锁续上新的时长。

8.6 Redlock

单机锁在 Redis 主节点宕机时可能失效。

Redlock 的思路是向多个独立的 Redis 主节点依次加锁,只有超过半数的节点加锁成功才算获取锁,任一节点故障都不影响整体判定,安全性更高:

例如图中 5 个主节点,线程一在多数节点加锁成功即持有锁;获取失败的节点视为超时,不影响其他线程正常加锁。

九、常见面试题

挑选几条高频问题整理:

9.1 Redis 有哪些特点?

高性能内存存储、支持多种数据结构、支持持久化、单线程处理请求、支持主从复制、哨兵与集群模式、支持事务与多语言客户端。

与 MySQL 这类关系型数据库相比,Redis 没有复杂查询与约束,换来的是简单易用与更高性能。

9.2 Redis 为什么是单线程模型?

Redis 的性能瓶颈通常在内存与 IO 而非 CPU。单线程避免线程切换与竞态消耗,配合纯内存访问和 epoll 实现 IO 多路复用,足以支撑每秒万级别的处理能力。

9.3 过期删除与内存淘汰有什么不同?

过期删除针对“已设置过期时间的 key”,Redis 同时使用惰性过期(访问时判断是否过期)与定期过期(周期性抽查清理)两种策略;内存淘汰针对“内存写满”的情况,按配置策略从过期 key 或全部 key 中挑选数据淘汰。

9.4 RDB 与 AOF 怎么选?

RDB 是二进制快照,恢复快、适合备份,但最后一次快照之后的数据可能丢失;AOF 记录写命令,数据完整性更好,代价是文件体积与恢复开销。生产环境常两者结合,4.0 起的混合持久化同时兼顾两者优势。

9.5 主从复制与哨兵、集群是什么关系?

主从复制解决数据冗余与读写分离;哨兵在主从基础上增加监控与自动故障转移,解决高可用;集群把数据分片到多组主从节点,解决容量与吞吐的水平扩展。三者的作用层层递进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询