Skip to main content

高并发组件概览:缓存与消息队列

本章节为全栈架构层面的概览,关于 Redis 的具体数据结构和底层原理,请参考 数据库章节 - Redis

当全栈项目面临用户量激增、并发请求变高时,单靠优化 Node.js 代码或增加 MySQL 索引已经捉襟见肘。这时候,必须在架构中引入缓存(Redis)消息队列(MQ)来化解数据库的压力。

1. 缓存层:Redis 在全栈架构中的角色

Redis 是内存级数据库,读写速度远超 MySQL。在架构中引入 Redis 的核心目的就是保护 MySQL

常见的 Redis 应用场景

除了作为 Session 存储和简单的键值缓存,全栈工程师还需要了解以下进阶用法:

  1. 分布式锁:当 Node.js 采用 Cluster 模式或多实例部署时,多个进程可能同时去修改同一份数据(如:同时发起抽奖)。需要使用 Redis 的 SETNX (Set if Not eXists) 实现分布式锁,确保同一时刻只有一个进程能执行该逻辑。
  2. 排行榜与计数器:利用 Redis 的 ZSET (有序集合) 极速实现游戏排行榜;利用 INCR (原子加) 实现高并发下的文章点赞数、视频播放量统计。
  3. Pub/Sub (发布订阅):在 WebSocket 多实例部署时,解决跨进程的事件广播问题。

面试高频:缓存的三大经典问题

在引入缓存后,系统变得复杂,全栈工程师必须知道如何应对以下极端情况:

  • 缓存穿透:查询一个根本不存在的数据。缓存中没有,导致请求全部打到数据库。
    • 防御:对空结果也进行短暂缓存;或者使用布隆过滤器 (Bloom Filter) 拦截。
  • 缓存击穿:一个极度热点的数据在缓存过期的瞬间,大量并发请求同时涌入,直接压垮数据库。
    • 防御:使用分布式锁(互斥锁),只让第一个请求去查数据库并重建缓存,其他请求等待。
  • 缓存雪崩大量缓存同时过期,或者 Redis 宕机,导致数据库瞬间面临巨大压力。
    • 防御:给缓存的过期时间加上一个随机值,避免集中失效;保证 Redis 自身的高可用(主从+哨兵,或集群模式)。

2. 消息队列 (Message Queue) 的核心作用

当业务逻辑越来越复杂,接口响应时间越来越长时,消息队列(如 RabbitMQ, Kafka, 甚至 Redis 的 Stream)是提升全栈应用吞吐量的终极武器。

核心作用一:异步解耦

场景:用户注册成功后,需要发送欢迎邮件、发放新手优惠券、初始化积分账户。

  • 未使用 MQ:Node.js 需要在注册接口中同步执行这三个操作,耗时极长,任何一步失败都可能导致注册失败。代码严重耦合。
  • 使用 MQ:Node.js 只负责将用户信息写入数据库,然后向 MQ 发送一条“用户已注册”的消息,立刻返回响应给前端(耗时极短)。后续的邮件、优惠券、积分服务独立订阅这个消息并在后台异步处理。

核心作用二:削峰填谷

场景:秒杀活动或抢购,瞬间涌入 10 万个请求。

  • 未使用 MQ:Node.js 实例和 MySQL 直接被洪峰流量压垮。
  • 使用 MQ:前端请求到达 Node.js 后,Node.js 不直接操作数据库,而是将所有请求全部打包成消息丢进 MQ 中(这个动作极快)。然后,后台的订单处理服务根据数据库的承受能力,平缓地从 MQ 中拉取消息进行处理(削峰)。

全栈视角的注意事项: 引入 MQ 会大幅增加系统的复杂度,你需要考虑:消息丢失怎么办?(可靠性保证)消息重复消费怎么办?(幂等性设计)。对于普通规模的全栈项目,不要盲目引入重量级 MQ,可以先用 Redis 充当简单的队列满足初步需求。