消息队列
消息队列在生产者与消费者之间保存并传递工作。本文比较 Kafka 4.1 普通消费者组与 RabbitMQ 4.1 队列。范围是日志、路由、保留与选型。
1. 面试核心
先记住这几条,再读正文- Kafka 日志模型。 Kafka 按 partition 保存日志,普通消费组用 offset 管理进度。卡 · Kafka 分区日志
- RabbitMQ 路由模型。 RabbitMQ exchange 根据 binding 将消息路由到 queue。
- 保留与重放。 Kafka 的日志保留独立于消费进度,compact 按键保留最新状态。卡 · 保留与日志压缩
- 消费组分工。 普通消费组内,一个 partition 同时分配给一个消费者。
- 削峰容量。 削峰依赖队列容量与消费余量,持续入流超出消费能力会积压。
2. 消息队列的作用
生产者发布工作后,消费者按容量异步处理。队列吸收短时速率差,也隔离部分服务故障。代价是结果延迟和新的失败恢复流程。
异步发布后,业务需区分已接收、已处理和最终完成。接口可以返回任务标识,再提供结果查询。
3. Kafka 分区日志
topic 包含多个 partition。record 在分区中按 offset 排列。消费读取不删除记录,清理策略决定保留范围。
普通 consumer group 独立保存消费进度。不同组可以各自读取同一份数据。同组一个 partition 同时分配给一个 consumer。消费者多于分区时,多出的消费者空闲。
本节讨论 KafkaConsumer 的普通消费者组。Kafka 4.1 的 Share Groups 使用另一套共享投递机制。它不适用上述独占分区的消费模型。
4. RabbitMQ 路由
生产者将消息发布到 exchange。exchange 根据类型、routing key 和 binding 选择队列。一个发布可进入多个已匹配队列。
| exchange 类型 | 匹配方式 |
|---|---|
| direct | routing key 精确匹配 binding key。 |
| topic | 按点分词匹配,* 匹配一个词,# 匹配零个或多个词。 |
| fanout | 路由到所有绑定队列。 |
| headers | 按头部属性和匹配规则选择队列。 |
同一队列的多个消费者分担消息。多个独立业务组应使用各自队列。常规队列消息确认后可删除;RabbitMQ Streams 则采用保留日志模型。
5. 消费进度
Kafka 的 position 是下一条待返回的记录位置。committed offset 是故障恢复使用的位置。手动提交时,应提交连续完成范围之后的下一个位置。
RabbitMQ 手动确认模式保留未确认投递状态。Channel 或连接关闭后,未确认消息会重新入队。确认具体时机见消息可靠性。
6. 保留与日志压缩
Kafka topic 的 cleanup.policy=delete 按时间或大小清理 segment。消费者落后过久时,所需旧数据会被清除。重放范围受保留策略约束。
cleanup.policy=compact 在后台保留各键的较新记录。压缩保留记录顺序和原 offset,清理后 offset 可以有空洞。键对应的 null 值是删除标记,即 tombstone。
tombstone 也有保留期限。落后太久的消费者会错过删除标记。因此压缩日志适合恢复最新键状态,完整历史审计需另行保留事件。
7. 消息顺序
Kafka 分区内按 offset 有序。业务完成顺序还取决于分区映射和消费并发。重复、重新入队和版本处理见消息幂等性。
8. 投递语义
| 语义 | 结果约束 |
|---|---|
| At-most-once | 每条至多处理一次,失败允许漏处理。 |
| At-least-once | 保证重试交付,消费者要接受重复。 |
| Exactly-once | 在明确定义的提交边界内产生一次有效结果。 |
交付保证依赖持久化、保留和恢复条件。Kafka 事务的适用范围见消息幂等性。
9. 选型
| 需求 | 重点比较 |
|---|---|
| 事件流长期保留、多组独立重放 | Kafka 分区日志与保留策略。 |
| 按键维护最新状态 | Kafka compact 与 tombstone 窗口。 |
| 复杂消息路由、逐条任务确认 | RabbitMQ exchange、queue 与 ack。 |
| 短时流量削峰 | 队列容量、消费余量和消息时效。 |
Kafka 可通过分区、批量和顺序 I/O 扩展吞吐。RabbitMQ 便于表达多种路由与逐条投递控制。选型还需验证客户端、故障恢复和运维成本。
10. 常见问题
10.1 Kafka 的队列用途
一个普通消费组可分担 topic 的处理工作。多个组则独立读取相同日志。消息生命周期由保留策略控制。
10.2 削峰容量
若每秒生产 2000 条、消费 1500 条,每秒积压 500 条。持续 60 秒就积压 30000 条。峰值结束后还需有消费余量才能清空。
应同时监控消息数量和最老消息年龄。最老年龄更接近业务等待体验。
11 · 面试题卡片
本页题目与参考回答
11.1 Kafka 和 RabbitMQ 的模型有什么区别,应该如何选择
出现公司:快手
考察重点
- 分区日志、offset、exchange、queue 与 acknowledgement。
- 保留重放、路由和顺序边界。
- 投递语义与外部副作用。
相关内容:Kafka 分区日志至选型。
参考回答
Kafka 保存分区日志,消费组用 offset 管理进度。
记录可在保留范围内重放。RabbitMQ 用 exchange 和 binding 路由到队列,再逐条投递确认。
长期事件流和多个独立消费视图适合比较 Kafka。复杂路由和任务确认适合比较 RabbitMQ。选择还要考虑保留、顺序和恢复条件。外部业务副作用需独立设计幂等。
11.2 Kafka 消费后还能一直重放吗,compact 保留全部历史吗?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:保留窗口、键状态与 offset 空洞。
相关内容:保留与日志压缩。
参考回答
重放范围受日志保留和清理策略约束。
delete 可删除过期 segment,即使消费者尚未读取。compact 清理同键旧记录,保留最新状态所需的数据。原 offset 保持不变,因此日志中会出现空洞。