返回首页

RabbitMQ 与 Kafka 入门教程:任务队列还是事件流?

技术· 2026/7/16· 2 阅读

目录

RabbitMQ 与 Kafka 入门教程:任务队列还是事件流?

做后端时总会碰到这类需求:接口要尽快返回,但后面还有抓取、写日志、发通知等「慢活」。如果全堆在一次 HTTP 请求里,接口会变慢,高峰时还容易把服务打挂。

消息中间件就是把「发出任务」和「真正干活」拆开:业务先把消息丢进中间件,消费者再慢慢处理。市面上最常被拿来对比的两套方案,就是 RabbitMQKafka

本文用尽量少的概念,讲清二者分别擅长什么,以及本站(NestJS 博客)里为什么一个用 RabbitMQ、一个用 Kafka。


1. 先记住一个判断题

你更像在做…… 更合适
「帮我办一件事」:抓取、转码、发邮件、扣积分 RabbitMQ(任务队列)
「记下一串发生过的事」:访问日志、埋点、审计流 Kafka(事件流 / 日志)

一句话:

  • RabbitMQ:消息像待办工单,处理完通常就没了(消费确认后删除)。
  • Kafka:消息像账本,写进去后还能按偏移量重放、多组消费者各自读。

两者都能做异步,但心智模型和运维成本不一样。


2. 为什么要用中间件?

没有中间件时,常见写法是:

text 复制代码
用户请求 → 接口里同步抓网页 → 写库 → 再返回

问题很直观:

  1. :抓取、第三方 API 一卡,用户就一直转圈。
  2. :下游挂了,接口也一起失败。
  3. 难扩:流量突增时,只能把整台 API 机器一起扩,无法单独扩「干活」的进程。

有了队列之后:

text 复制代码
用户请求 → 入队成功就返回 → 消费者异步处理 → 写库 / 回调

API 只负责「登记任务」,真正耗时的工作交给消费者,峰值被缓冲在队列里。


3. RabbitMQ 入门

3.1 核心概念(够用即可)

text 复制代码
Producer(生产者)
    ↓
Exchange(交换机:按规则把消息分发出去)
    ↓
Queue(队列:真正存消息的地方)
    ↓
Consumer(消费者:取出并处理)

初学时最常见的模式是:生产者直接往某个队列发消息(内部往往是默认交换机 + 路由键等于队列名)。你只需要记住:

  • Queue:待办列表。
  • Consumer:工人。多个工人可以抢同一队列的任务(竞争消费)。
  • ACK:处理成功再确认;失败可不确认或拒绝,消息可重新入队。

3.2 适合做什么?

  • 书签 / 友链全量抓取
  • 视频去水印解析
  • 邮件、短信、Webhook
  • 需要「做完就完」的后台任务

特点是:任务有明确终点,积压可以看队列长度,处理完消息通常不再保留。

3.3 本站里的 RabbitMQ

本站开启 RABBITMQ_ENABLED=true 后,用 AMQP 连接 Broker,主要队列包括:

队列名 用途
blog.crawl.bookmark 书签全量抓取
blog.crawl.friend-link 友链可达性 / 元信息刷新
blog.mp.video-watermark 小程序视频去水印任务

管理后台仪表盘会展示这些队列的积压;健康检查也会探测 RabbitMQ 是否可达。

未配置 RABBITMQ_URL 时,代码会回退到进程内异步,本地开发不装 RabbitMQ 也能跑通主流程。

3.4 本地快速体验(Docker)

bash 复制代码
docker run -d --name rabbitmq \
  -p 5672:5672 -p 15672:15672 \
  rabbitmq:3-management

浏览器打开 http://localhost:15672(默认账号密码一般是 guest / guest),就能看到队列、连接和消息吞吐。生产环境请改掉默认账号,并限制管理端口的公网访问。


4. Kafka 入门

4.1 核心概念

text 复制代码
Producer → Topic(主题,可分成多个 Partition)
                ↓
         Consumer Group(消费组)

关键点:

  • Topic:一类事件的名字,例如 blog.api-request-logs
  • Partition:分区。同一分区内有序;多分片可并行消费。
  • Offset:消费进度,像书签一样记「读到哪一行」。
  • Consumer Group:同一组内的实例分摊分区;不同组可以各自完整消费同一 Topic(互不影响)。

Kafka 把消息更像追加写的日志:默认会保留一段时间(或按体积),而不是「消费完立刻删」。

4.2 适合做什么?

  • 高吞吐写入:接口日志、埋点、审计
  • 需要回放 / 多下游订阅同一数据流
  • 后续接数仓、实时统计、告警分析

不太适合当成「简单任务队列」的首选:运维(ZooKeeper / KRaft、磁盘、分区规划)比 RabbitMQ 重一截。

4.3 本站里的 Kafka

本站接口请求日志原先走 Redis List 批量刷库;接入 Kafka 后变成:

text 复制代码
请求结束 → produce 到 blog.api-request-logs
         → consumer group blog-api-logs 批量 createMany 入库

相关配置大致是:

env 复制代码
KAFKA_ENABLED=true
KAFKA_BROKERS=127.0.0.1:9092
KAFKA_CLIENT_ID=blog-api
KAFKA_API_LOG_TOPIC=blog.api-request-logs
KAFKA_API_LOG_GROUP=blog-api-logs

未启用 Kafka 时,自动回退 Redis + 定时 flush,保证日志链路不断。

PM2 多实例时,同一 Consumer Group 会分摊分区,正好匹配「多进程消费同一条日志流」的场景。


5. 一张表对比

维度 RabbitMQ Kafka
模型 队列 / 交换机 分区日志
消息寿命 通常消费后删除 按策略保留,可重放
吞吐 中等,够大多数业务任务 更高,偏流式写入
多订阅者 要 fanout / 多队列复制 天然:多 Consumer Group
运维复杂度 相对轻 相对重
典型场景 异步任务、RPC 解耦 日志、埋点、事件溯源

不是二选一消灭对方:本站就是并存——任务走 RabbitMQ,日志流走 Kafka。


6. 接入时容易踩的坑

  1. 把 Kafka 当小队列用
    只有一两个消费者、消息量不大、也不需要重放时,RabbitMQ(或 Redis 队列)往往更简单。

  2. 忘记失败处理
    RabbitMQ 要设计 ACK / 重试 / 死信;Kafka 要明确「处理失败是否提交 offset」,避免丢消息或死循环。

  3. 本地和线上行为不一致
    本站做法是:中间件可选,未启用则回退。开发机不装 Broker 也能写业务,但联调队列行为时仍建议起 Docker。

  4. 只入队不消费
    CLI 或临时脚本若开启「只发布」,记得别在生产主进程上误关消费者,否则积压会一直涨。

  5. 安全组与管理台
    5672 / 9092 / 15672 不要无脑对公网全开;管理台建议仅内网或加鉴权。


7. 怎么在自己的项目里落地(最小步骤)

RabbitMQ 任务

  1. 安装 Broker,创建 vhost / 用户。
  2. 业务侧:publish(queue, payload)
  3. 消费者:consume → 处理 → ack
  4. 监控队列长度;积压告警。

Kafka 日志流

  1. 起 Broker(单节点学习可用 KRaft 或现成发行版)。
  2. 创建 Topic(分区数按消费者规模预估)。
  3. 请求链路 produce;独立 consumer group 批量落库。
  4. 观察 consumer lag(积压 = 日志末端偏移 − 组已提交偏移)。

本站管理后台的「消息队列」面板,就是在看 Rabbit 队列深度和 Kafka lag,方便一眼判断有没有堵。


8. 小结

  • 要异步办事 → 先想 RabbitMQ(或同类任务队列)。
  • 要高吞吐记账 / 多下游读同一流 → 再上 Kafka。
  • 选型看问题形态,不看谁「更流行」。
  • 生产环境务必:鉴权、限端口、可回退、可观测(积压 + 健康检查)。

如果你正在搭个人站点或中小型 NestJS 服务,完全可以像本站一样:RabbitMQ 扛爬虫与工具任务,Kafka 扛接口日志,两套职责清晰,出问题也好分别排查。


文中队列名、Topic 名对应本站当前实现;若你 fork 代码,以仓库 docs 与环境变量为准。

评论

暂无评论,来抢沙发吧