排行榜之后,我们来看 Redis 在「消息与异步解耦」里的角色。后端里经常需要「生产者发一条、消费者慢慢处理」:发邮件、发通知、写日志、扣库存等,若都在请求链路里同步执行,延迟与故障域都会放大; 把任务丢进队列、由后台异步消费,可以缩短响应时间、隔离故障。 Redis 的 List 与 Stream 都能用来做「队列」,但能力与边界不同:List 简单、适合「快产快消」的轻量队列;Stream 支持消费者组、消息 ID、可回溯,更接近「消息中间件」。
我们先从 List 与 Stream 的适用场景说起,再落到简单消息队列的实现,最后讨论 Redis 与 Kafka 的边界,帮助你在选型时看清取舍。
Redis 的 List 是双向链表:LPUSH/RPUSH 从左侧或右侧插入,LPOP/RPOP 从左侧或右侧弹出,BLPOP/BRPOP 在空队列时阻塞等待。用它做队列时,生产者 LPUSH 到队头,消费者 RPOP 从队尾取(或反过来),即可实现 FIFO;消费者用 BRPOP 阻塞等待,有消息就取、没有就等,无需轮询。List 的优点是实现简单、延迟低、命令少;缺点是「一条消息只能被一个消费者取走」,没有「多消费者组」「消息确认」「回溯」等能力,且消息取出即从 List 中删除,若消费者处理失败,消息就丢了,除非应用层自己再写回队列或死信队列。
Stream 是 Redis 5.0 引入的「仅追加日志」结构:XADD 往 Stream 里追加一条消息(带自动生成的 ID),XREAD 按 ID 往后读,XREADGROUP 在消费者组内按组消费。Stream 支持消费者组:同一 Stream 可被多个组消费,组内多个消费者分摊消息,每条消息在组内只被消费一次;支持消息确认(XACK)与待处理列表(XPENDING),消费失败可重新投递;支持按 ID 回溯,新消费者可从历史位置开始读。因此,Stream 适合「需要多组消费、需要确认与重试、允许回溯」的场景,例如任务队列、事件分发;List 适合「单消费者、快产快消、允许丢消息」的轻量场景,例如实时通知、简单异步任务。

用 List 做简单消息队列时,通常一个 Key 对应一条队列:生产者 LPUSH 将任务序列化后写入 Key(如 queue:email),消费者 BRPOP 从该 Key 取任务,取到后反序列化并执行逻辑;若执行失败,可将任务再 LPUSH 回队列或写入「死信」队列,由应用层约定重试策略。BRPOP 支持超时(如 BRPOP queue:email 5),超时返回空,避免永久阻塞;多队列时可写 BRPOP queue:email queue:sms 5,任一队列有消息即返回。注意 List 没有「主题」或「分区」,多业务需用多 Key 或 Key 前缀区分;单 Key 内消息是 FIFO,无法按优先级或延迟投递,若有这类需求需用 Sorted Set(score 为执行时间)或 Stream。
用 Stream 做消息队列时,生产者 XADD 往 Stream 里追加消息(字段可自定义,如 task、payload、created_at),消费者用 XREAD 阻塞读新消息(BLOCK 0 表示一直等),或使用 XREADGROUP 加入消费者组,由组内多个消费者分摊。XREADGROUP 会为每条消息生成「待确认」记录,消费者处理完后 XACK 确认,未确认的消息会留在 PEL(Pending Entries List),可被其他消费者 CLAIM 或超时重投。这样,同一条消息在组内只被消费一次,且支持失败重试与回溯;适合「多实例消费、需要至少一次语义」的任务队列。
|LPUSH queue:email '{"to":"a@b.com","subject":"..."}' BRPOP queue:email 5 XADD stream:tasks * task send_email to "a@b.com" payload "..." XREADGROUP GROUP workers consumer1 COUNT 10 BLOCK 5000 STREAMS stream:tasks 0 XACK stream:tasks workers <id>

Redis 的 List 与 Stream 都能做「队列」,但在存储介质、持久化、吞吐与生态上与 Kafka 等专业消息中间件有本质差异。Redis 数据主要在内存,虽有 AOF/RDB,但持久化以「故障恢复」为主,不会像 Kafka 那样按「保留 N 天」长期落盘;内存成本高,单机容量有限,消息堆积过多会占满内存或触发淘汰。Kafka 以磁盘为主,消息按分区顺序写、顺序读,吞吐高、成本低,且支持多副本、多消费者组、精确一次语义等,适合「海量消息、长期保留、多消费者组、强可靠」的场景。
选型时可以这样划界:若消息量不大、允许丢失、希望实现简单、延迟极低,用 Redis List 或 Stream 即可,例如应用内的异步任务、实时通知、轻量事件。若消息量大、不能丢、需要长期保留与回溯、多组消费与复杂路由,应选 Kafka 或同类中间件,Redis 只作为缓存或会话等角色,不承担「消息中枢」的职责。Redis Stream 的消费者组与 Kafka 的消费者组在语义上类似,但 Redis 没有分区、没有多副本、没有跨节点的高可用与水平扩展,规模一大就会碰到单机瓶颈;因此,Redis 适合「小规模、快产快消、可接受丢消息」的队列,Kafka 适合「大规模、高可靠、多组多分区」的消息总线。

从消息与异步解耦延伸出去,Redis 还能做发布订阅(Pub/Sub),但 Pub/Sub 不持久化、不存消息,订阅者不在线就收不到,适合「实时广播、允许丢」的场景,与「队列」的语义不同。下一讲我们会看 Redis 的事务与原子性:MULTI/EXEC、原子操作的意义,以及为什么 Redis 不支持回滚。