ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Kafka 和 MQ 到底什么时候用?从任务队列、事件流到分布式系统真正理解消息中间件

2026/8/17 22:28:36 拓冰建站 浏览量
Kafka 和 MQ 到底什么时候用?从任务队列、事件流到分布式系统真正理解消息中间件 学后端时MQ 和 Kafka 是两个非常容易混淆的东西。刚开始看会发现它们长得几乎一样Producer ↓ 消息中间件 ↓ Consumer都有生产者都有消费者都能发送消息。于是很容易产生几个疑问Kafka 和 MQ 不都是生产消息、消费消息吗Kafka 消费以后还能重新消费那是不是比 MQ 更强既然 Kafka 什么都能做那为什么还要 MQ真正理解 Kafka 和 MQ不能从 Producer、Consumer、Broker 这些名词开始而应该先理解它们分别想解决什么问题。可以先记住两个最简单的概念MQ 更像任务队列。Kafka 更像分布式系统中的事件流水。这两个概念一旦建立起来后面的 Queue、Topic、Partition、Offset、Consumer Group 就会容易很多。一、先理解最普通的 MQ假设系统需要生成一份机器人清扫报告。用户在 App 中点击生成清扫报告如果生成 PDF 要花 5 秒钟接口完全可以同步执行App ↓ Spring Boot ↓ 生成 PDF ↓ 5 秒以后 ↓ 返回 App但这样用户就得一直等待。更常见的做法是App ↓ Spring Boot ↓ MQ ↓ 报告服务 ↓ 生成 PDFSpring Boot 只是往 MQ 中扔一个任务给机器人 001 生成清扫报告然后直接告诉 App任务已提交后台的报告服务再慢慢处理。因此这里 MQ 中保存的东西本质上是等待某个消费者完成的任务。可以暂时把 MQ 理解成MQ 任务队列二、MQ 没有消费者会怎么样假设 Producer 连续发送三条消息Producer ↓ A B C ↓ Queue如果这时候没有 Consumer消息并不会凭空消失。而是Queue [A] [B] [C]暂时排在那里。过一会消费者启动Consumer ↓ 取出 A ↓ 处理成功 ↓ ACK然后取出 B 取出 C直到任务全部完成。因此 MQ 很像一个任务待办池。没人处理的时候任务先排队有人处理的时候取任务 ↓ 执行 ↓ 成功 ↓ ACK所以 MQ 里的消息并不是必须立刻消费。恰恰相反“先存着等消费者有能力的时候再处理”本身就是 MQ 存在的重要意义。三、为什么业务系统里经常需要 MQ例如用户下单以后可能需要同时做很多事情创建订单 发送短信 发送邮件 增加积分 发送优惠券 通知仓库如果全部同步执行用户 ↓ 订单服务 ↓ 短信服务 ↓ 邮件服务 ↓ 积分服务 ↓ 仓库服务 ↓ 返回整个接口会越来越慢。于是可以变成用户下单 ↓ 订单保存成功 ↓ 发送 MQ 消息 ↓ 立即返回后台MQ ↓ ┌───────┼────────┐ ↓ ↓ ↓ 短信服务 积分服务 其他服务这样订单服务就不需要等待所有业务执行完成。这就是 MQ 一个非常典型的作用异步把不需要立即完成的事情放到后台执行。除此之外MQ 还有两个非常重要的作用。四、MQ 可以用来解耦假设订单服务直接调用短信服务订单服务 ↓ 短信服务订单服务必须知道短信服务在哪里 短信接口是什么 短信服务有没有挂以后又增加邮件订单服务 ├→ 短信服务 └→ 邮件服务再增加积分订单服务 ├→ 短信 ├→ 邮件 └→ 积分订单服务和越来越多系统发生依赖。如果改成订单服务 ↓ MQ订单服务只需要告诉系统订单创建成功至于谁处理由消费者自己决定。这样系统之间的依赖就降低了。这就是解耦。五、MQ 还可以削峰假设 MySQL 最多能够稳定处理1000 个请求 / 秒突然秒杀活动来了10000 个请求 / 秒如果所有请求直接进入 MySQL10000 请求 ↓ MySQL数据库很可能被瞬间打垮。这时候可以在中间增加 MQ10000 请求 ↓ MQ ↓ 消费者按照系统能力处理 ↓ 1000 / 秒 ↓ MySQLMQ 就像一个水库。洪峰先进入水库10000再按照下游能够接受的速度慢慢放出去1000 1000 1000 ...这就是削峰填谷。所以业务系统里 MQ 的使用场景其实非常多。常见的有发送短信 发送邮件 生成报表 图片处理 异步计算 延迟任务 订单处理 失败重试 削峰这些场景有一个共同特点系统希望某件事情最终被执行完成。六、Kafka 解决的问题开始不一样了再来看机器人系统。机器人运行过程中会不断产生数据10:00:01 位置 A 电量 80% 10:00:02 位置 B 电量 80% 10:00:03 位置 C 电量 79% 10:00:04 位置 D 电量 79%机器人还可能不断产生位置变化 速度变化 任务状态 电量变化 设备上线 设备掉线 故障 运行日志 传感器数据这些东西和生成一份 PDF完全不是一个性质。生成 PDF 是请别人帮我完成一个任务。机器人位置变化则是系统刚刚发生了一件事情。这就是 Kafka 开始擅长的领域事件。七、Kafka 可以理解成一份不断追加的事件流水假设机器人不断产生事件offset 0 RobotConnected offset 1 PositionChanged offset 2 BatteryChanged offset 3 PositionChanged offset 4 RobotError offset 5 PositionChangedKafka 会把这些事件不断追加进去。可以把它想象成一个巨大的日志0 1 2 3 4 5 6 7 8 ...消费者并不是简单地把里面的数据“拿走”。而是在读取我现在读到哪里了例如状态服务已经读到 offset 5数据分析服务读到 offset 3日志服务读到 offset 5它们各自拥有自己的消费进度。这就是 Kafka 和传统任务队列非常不一样的地方。八、为什么 Kafka 消费完还能重新消费传统 MQ 可以先粗略理解成消息 ↓ Queue ↓ Consumer ↓ 处理成功 ↓ ACK ↓ 任务结束MQ 更关注这个任务有没有被处理成功Kafka 则更像事件 ↓ 写入 Kafka ↓ 保存在 Partition 中 ↓ Consumer 读取 ↓ 记录 offset消费者读完以后并不意味着这条数据立即被删除。Kafka 中的数据一般按照时间 容量 保留策略等规则保存。因此原来消费者offset 100完全可以重新调整到offset 50然后50 51 52 53 ... 100重新读取。所以 Kafka 的消费更像读日志。而不是把任务取走。九、Kafka 为什么特别适合分布式、多进程系统这其实是理解 Kafka 非常重要的一步。现代后端往往不是只有一个进程。例如机器人云平台可能有设备状态服务 告警服务 日志服务 任务服务 数据分析服务 轨迹服务这些都是不同服务 不同进程 甚至部署在不同服务器现在机器人发生了一件事情Robot001 电量降低到 20%很多服务都想知道状态服务 我要更新当前电量 告警服务 我要判断是否低电量报警 日志服务 我要记录 数据分析服务 我要拿去统计如果机器人分别调用四个系统Robot ├→ 状态服务 ├→ 告警服务 ├→ 日志服务 └→ 分析服务系统耦合会非常严重。于是可以变成Robot001 BatteryChanged(20%) ↓ Kafka ↓ ┌──────┼──────┬──────┐ ↓ ↓ ↓ ↓ 状态 告警 日志 数据分析 服务 服务 服务 服务机器人只产生一次事件。Kafka 把这份事件流提供给多个独立消费者。每个消费者按照自己的速度读取并且互相不影响因此 Kafka 非常适合分布式系统中让多个独立服务/进程消费同一份事件数据流。这个理解比简单说Kafka 是消息队列。要更加接近 Kafka 的实际价值。十、但 Kafka 不是“共享变量”这里有一个容易继续混淆的地方。既然多个进程都能从 Kafka 获取数据那么是不是Kafka 就是分布式共享数据不能完全这么理解。假设多个服务想知道Robot001 当前是否在线或者用户当前登录 Session 是什么或者某个 Token 是否有效这些关注的是当前值。这种情况下Service A ─┐ Service B ─┼──→ Redis Service C ─┘Redis 往往更合适。Kafka 更关注Robot001 什么时候上线了 什么时候掉线了 什么时候再次上线了它保存的是事情发生的过程。因此可以形成一个非常重要的区分。十一、Redis 和 Kafka 的区别现在是什么 vs 发生过什么例如Robot001 当前电量20%这是一个当前状态可以放 Redis。而10:00 电量 30% 10:10 电量 25% 10:20 电量 20%这是状态变化事件流可以进入 Kafka。所以可以简单记成Redis 现在是什么而Kafka 发生过什么这两个东西解决的问题其实完全不同。十二、再把 MySQL 放进来这时候就能把几个后端常见组件放到一起理解了。假设机器人系统中存在这些数据。机器人基本资料机器人名称 SN 设备型号 所属用户 创建时间这些是正式业务数据→ MySQL机器人当前状态在线 当前电量 当前任务 当前坐标这些经常读取而且变化频繁→ Redis机器人运行事件上线 掉线 位置变化 电量变化 故障 日志 传感器数据这些形成持续的数据流→ Kafka后台任务生成报告 发送短信 发送邮件 图片处理这些是等待执行的任务→ MQ于是系统开始变得非常清楚。十三、完整来看四种组件可以形成这样的第一层架构直觉分布式系统 正式业务数据 ↓ MySQL 当前共享状态 ↓ Redis 异步业务任务 ↓ RabbitMQ / RocketMQ 大量事件数据流 ↓ Kafka可以进一步记成四句话MySQL 业务最终是什么Redis 现在是什么MQ 有什么事情需要做Kafka 刚刚发生了什么这四句话非常适合建立后端系统的第一层架构认知。十四、机器人系统中的完整例子假设机器人现在电量从21%变成20%机器人上报BatteryChanged robotId 001 battery 20事件进入 KafkaRobot ↓ Kafka然后多个系统消费Kafka ↓ ┌─────────┼──────────┐ ↓ ↓ ↓ 状态服务 告警服务 数据分析状态服务更新 Redis robot001:battery 20告警服务发现battery 20%于是产生一个任务发送低电量通知这个任务进入 MQ告警服务 ↓ MQ ↓ 通知服务 ↓ 发送 Push / 短信同时正式的告警记录写入 MySQL最终整个链路就是Robot ↓ BatteryChanged ↓ Kafka ↓ 告警服务 ↓ 发现低电量 ↓ MQ ↓ 通知服务 同时 状态服务 → Redis 告警记录 → MySQL到这里可以发现Kafka、MQ、Redis、MySQL 根本不是竞争关系。它们分别负责不同的问题。十五、MQ 和 Kafka 最核心的区别现在回过头看可以非常简单地总结。MQ更关注事情有没有被处理完成例如发送短信 发送邮件 生成报告 图片转换 后台计算因此可以粗略理解为Task ↓ MQ ↓ Consumer ↓ 完成任务Kafka更关注系统发生了什么哪些服务需要获取这些事件例如设备上线 设备掉线 机器人位置变化 用户点击 订单状态变化 系统日志 传感器数据因此可以理解为Event ↓ Kafka ↓ 多个独立服务 ↓ 按照自己的进度消费十六、Kafka 并不是“更高级的 MQ”这是非常容易出现的误区。看到 Kafka吞吐量高 可以持久化 可以重复消费 可以多个消费者读取很容易产生既然 Kafka 什么都能做为什么还需要 MQ事实上正确的问题并不是Kafka 和 MQ 谁更厉害而应该是我现在解决的是任务处理问题 还是事件流问题如果是帮我完成一件事情。优先想到MQ如果是系统发生了一件事情我需要让多个分布式服务知道。而且数据量大 持续产生 需要保留 可能重复读取 多个消费者独立消费那么 Kafka 就非常合适。当然实际系统并不是绝对的Kafka 也可以承担某些异步任务RabbitMQ、RocketMQ 也支持发布订阅。但作为学习阶段的第一层架构判断MQ 任务队列Kafka 分布式事件流水这个模型非常实用。十七、最后形成一张完整的架构图以机器人云平台为例机器人云平台 Robot ↓ 位置 / 电量 / 状态 / 日志 / 故障 ↓ Kafka ↓ ┌───────────┬────────────┬─────────────┐ ↓ ↓ ↓ ↓ 状态服务 告警服务 日志服务 数据分析 ↓ Redis 保存当前状态 告警服务 ↓ 发现需要通知 ↓ MQ ↓ 通知服务 ↓ Push / 短信 / 邮件 设备资料 / 用户 / 任务 / 告警记录 ↓ MySQL这时候几个组件的位置就非常清楚Redis → 当前共享状态 MySQL → 正式业务数据 MQ → 等待执行的任务 Kafka → 分布式服务共享的事件数据流十八、总结最开始学习 MQ 和 Kafka 时很容易陷入Producer Consumer Queue Topic Broker Partition Offset Consumer Group ACK这些技术名词。但如果先从系统设计的角度理解会简单很多。遇到一个需求时可以先问这是需要别人完成的一件事情吗例如发短信 生成报告 处理文件考虑MQ这是系统中发生的一件事情吗例如机器人位置变化 设备掉线 电量变化 系统日志并且多个分布式服务都需要消费考虑Kafka我需要共享的是当前状态吗例如机器人当前在线状态 当前电量 Session Token考虑Redis这是最终需要长期保存的业务数据吗例如用户 设备 订单 任务 告警记录考虑MySQL最后可以浓缩成四句话MySQL业务数据最终是什么Redis现在是什么MQ有什么事情需要做Kafka刚刚发生了什么并且哪些分布式服务需要知道理解到这一层以后再学习 Broker、Partition、Offset、Consumer Group就不再只是背概念了。因为你已经知道这些机制最终都是为了让分布式系统中的任务和事件可靠地流动起来。