Express 里 Redis 怎么用:缓存、分布式锁、限流与常见库选择
面试速答(30 秒版)
- Redis 在 Express 项目里最常见的角色不是“数据库替代品”,而是 缓存、会话存储、计数器、分布式锁、消息协作。
- Node 侧常见库有两类思路:官方
redis客户端 和ioredis这类更偏工程化的客户端。 - 面试高频点是:为什么要上 Redis、适合缓存什么、缓存一致性怎么处理、限流和锁怎么落地。
- Express 和 Redis 的配合通常发生在 service 层或通用基础设施层,而不是每个 controller 里随手直连。
- 一句话总结:Redis 在 Express 体系里主要是为了解决“快读、削峰、共享状态和并发控制”问题。
一、先讲 Redis 在整条链路里的位置
很多人把 Redis 讲得很散。更好的方式是先说明它在服务里扮演什么角色。
这张图说明 2 个核心价值:
- Redis 可以缩短读路径。
- Redis 可以挡住数据库热点压力。
二、Express 项目里 Redis 最常见的几种用途
1. 缓存
最常见,也是面试第一反应点。
适合缓存的数据:
- 热点详情页
- 配置项
- 权限快照
- 首页聚合结果
- 验证码和短期状态
不适合直接缓存的数据:
- 强一致库存扣减结果
- 变化极高且命中率低的数据
- 对用户强隔离且组合维度爆炸的数据
2. Session / Token 辅助存储
例如:
- Session 集中存储
- Token 黑名单
- 登录态续期
3. 限流与计数器
例如:
- 接口每分钟访问次数
- 登录失败次数
- 短信发送频率控制
4. 分布式锁
适用于:
- 防止定时任务重复执行
- 控制某些关键资源的并发修改
但一定要补边界:
- 分布式锁不是银弹,设计不当会有误删锁、锁超时、时钟漂移等问题。
三、Node 里常见 Redis 库怎么选
1. redis
特点:
- 官方生态
- 常规场景足够
- API 较直接
2. ioredis
特点:
- 在很多团队里更常见于复杂场景
- 对集群、哨兵、重连等工程能力支持常被提及
面试不必纠结“谁绝对更好”,更稳的说法是:
- 简单场景看团队习惯即可;复杂部署和运维要求更高时,会更关注客户端的工程能力。
四、缓存怎么讲才不浅
1. 不只是“查不到就回源”
最基本的缓存读取流程:
const cacheKey = `user:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const user = await getUserFromDb(userId);
await redis.set(cacheKey, JSON.stringify(user), {
EX: 300,
});
return user;
但面试里别停在这里,因为这只是入门。
2. 还要讲 3 类经典问题
- 缓存穿透
- 缓存击穿
- 缓存雪崩
缓存穿透
查询一个本来就不存在的数据,请求次次打到数据库。
常见应对:
- 参数校验
- 布隆过滤器
- 空值缓存
缓存击穿
某个热点 key 失效瞬间,大量请求同时回源。
常见应对:
- 热点不过期或逻辑过期
- 单飞控制
- 互斥锁
缓存雪崩
大量 key 同时过期,数据库瞬时被打爆。
常见应对:
- 过期时间加随机值
- 多级缓存
- 限流降级
五、Redis 在 Express 里做限流怎么理解
限流本质是:
- 在一个时间窗口内控制某类请求次数。
典型维度:
- 按 IP
- 按用户 ID
- 按接口
实现常见依赖:
- 计数器
- 过期时间
- 原子递增
一个常见思路:
- 请求到来,按
userId + route生成 key。 - 用 Redis 原子递增。
- 第一次递增时设置过期时间。
- 超过阈值直接拒绝。
这类场景 Redis 的优势在于:
- 多实例共享计数状态。
六、分布式锁怎么答才不会翻车
面试官常会追问“Redis 分布式锁怎么实现”。
标准答法可以控制在这个粒度:
- 用唯一值尝试加锁。
- 设置过期时间,避免死锁。
- 释放锁时校验 value,保证只删自己的锁。
面试里最重要的是不要讲得过度绝对。
你应该主动补充:
- Redis 锁更适合短临界区和工程协作控制。
- 对金融级强一致场景,不能只靠一个“简单锁”就觉得万无一失。
七、Redis 键设计也是高频细节
键设计建议:
- 要有前缀,如
user:profile:123 - 带上业务域,方便排查和批量管理
- 避免过长、无规则、可读性差
值设计建议:
- 简单状态可直接字符串
- 复杂对象可 JSON,但要控制体积
- 热点大对象要谨慎,序列化和网络成本会变高
面试补一句很实用:
- Redis 优化不只是命中率,还包括 key 设计、数据体积和过期策略。
八、Express 项目里 Redis 应该放在哪一层
更合理的做法通常是:
- 在 service 层使用缓存接口
- 在基础设施层封装 Redis client
- controller 不直接堆 Redis 细节
原因:
- 避免业务代码到处散落缓存 key
- 便于统一超时、序列化、重试和错误处理
典型题与标准答法
1. 为什么 Express 项目经常配 Redis?
- 因为 Redis 能承担缓存、限流、会话共享、计数器和分布式锁等能力。
- 本质是减轻数据库压力并共享跨实例状态。
2. Redis 和数据库是什么关系?
- 一般不是替代关系。
- Redis 更偏高性能临时数据和协作能力,数据库仍然是核心持久化来源。
3. 缓存一致性怎么处理?
- 常见思路是更新数据库后删除缓存,或先更新数据库再异步刷新缓存。
- 重点在于控制脏读窗口和回源压力。
4. Redis 限流为什么适合多实例服务?
- 因为计数状态放在中心化的共享存储里,各个 Express 实例都能看到同一份数据。
常见追问
1. Redis 一定比数据库快吗?
- 大多数热点读场景下更快,但不能脱离数据模型、网络、序列化和命中率空谈。
2. 缓存 TTL 应该怎么定?
- 看数据变化频率、容忍脏数据时间和数据库承压能力。
- 不是越长越好,也不是越短越安全。
3. 所有查询都要加缓存吗?
- 不要。
- 低命中、低复用、变化快的数据加缓存可能只会增加复杂度。
易错点
- 把 Redis 说成“就是内存数据库”,答得太浅。
- 只会说缓存,不会说限流、锁和共享状态。
- 忽略穿透、击穿、雪崩。
- controller 到处直接拼 Redis key。
- 用了锁却不校验 value 就删除,埋下并发隐患。
速记要点
- Redis 在 Express 里主要解决缓存、限流、锁、会话和共享状态。
- 常见 Node 客户端是
redis和ioredis。 - 缓存题一定带上穿透、击穿、雪崩。
- 多实例限流和锁都依赖 Redis 的共享状态能力。
- Redis 要封装到基础设施或 service 层,不要散在 controller。