跳到主要内容

Express 里 Redis 怎么用:缓存、分布式锁、限流与常见库选择

面试速答(30 秒版)

  • Redis 在 Express 项目里最常见的角色不是“数据库替代品”,而是 缓存、会话存储、计数器、分布式锁、消息协作
  • Node 侧常见库有两类思路:官方 redis 客户端ioredis 这类更偏工程化的客户端。
  • 面试高频点是:为什么要上 Redis、适合缓存什么、缓存一致性怎么处理、限流和锁怎么落地
  • Express 和 Redis 的配合通常发生在 service 层或通用基础设施层,而不是每个 controller 里随手直连。
  • 一句话总结:Redis 在 Express 体系里主要是为了解决“快读、削峰、共享状态和并发控制”问题。

一、先讲 Redis 在整条链路里的位置

很多人把 Redis 讲得很散。更好的方式是先说明它在服务里扮演什么角色。

这张图说明 2 个核心价值:

  1. Redis 可以缩短读路径。
  2. 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
  • 按接口

实现常见依赖:

  • 计数器
  • 过期时间
  • 原子递增

一个常见思路:

  1. 请求到来,按 userId + route 生成 key。
  2. 用 Redis 原子递增。
  3. 第一次递增时设置过期时间。
  4. 超过阈值直接拒绝。

这类场景 Redis 的优势在于:

  • 多实例共享计数状态。

六、分布式锁怎么答才不会翻车

面试官常会追问“Redis 分布式锁怎么实现”。

标准答法可以控制在这个粒度:

  1. 用唯一值尝试加锁。
  2. 设置过期时间,避免死锁。
  3. 释放锁时校验 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 客户端是 redisioredis
  • 缓存题一定带上穿透、击穿、雪崩。
  • 多实例限流和锁都依赖 Redis 的共享状态能力。
  • Redis 要封装到基础设施或 service 层,不要散在 controller。