消息队列

面向 3-5 年经验 Java 后端开发,覆盖 Kafka/RocketMQ 选型、消息可靠性、顺序消费、积压处理等高频考点。
每道题包含中英双语答案、代码示例、常见误区和风控关联。
相关页面: Redis | 分布式系统 | Spring | 实时风控引擎

Q1. Kafka vs RocketMQ vs RabbitMQ 怎么选型?

EN: How do you choose between Kafka, RocketMQ, and RabbitMQ?

难度: ★★★★★ | 出现频率: 极高(阿里、美团、字节)

Key Terms: throughput (吞吐量), latency (延迟), message ordering (消息顺序), transaction message (事务消息), dead letter queue (死信队列), consumer group (消费者组)

答案要点:

维度 Kafka RocketMQ RabbitMQ
吞吐量 百万级 TPS 十万级 TPS 万级 TPS
延迟 ms 级 ms 级 μs 级
消息可靠性 高(副本 + ISR) 高(同步刷盘) 高(镜像队列)
顺序消息 Partition 内有序 Queue 内有序 Queue 内有序
事务消息 支持(exactly-once) 支持(半消息) 不支持
延迟消息 不支持(需外挂) 支持(18 级延迟) 支持(TTL + DLX)
消息回溯 支持(offset) 支持(时间戳) 不支持
适用场景 大数据/日志/事件流 电商/金融/事务 中小规模/低延迟

常见误区:

  • ❌ "Kafka 延迟最低,适合所有实时场景" → ✅ Kafka 吞吐量最高但延迟是 ms 级,RabbitMQ 延迟最低(μs 级),选型要按场景权衡吞吐与延迟
  • ❌ "Kafka has the lowest latency, so it fits all real-time scenarios" → ✅ Kafka has the highest throughput but ms-level latency; RabbitMQ offers the lowest latency (μs-level). The choice depends on the trade-off between throughput and latency
  • ❌ "选型只看性能指标就够了" → ✅ 选型还需考虑延迟消息/事务消息支持、运维复杂度、社区生态、团队技术栈等因素
  • ❌ "Choosing an MQ based solely on performance benchmarks" → ✅ Selection must also account for delayed/transactional message support, operational complexity, community ecosystem, and team expertise

延伸追问:

  • 如果你的系统同时需要高吞吐和事务消息,你会怎么设计架构?
  • Kafka 和 RocketMQ 在消息回溯能力上有什么差异?实际生产中有什么用?
  • How would you architect a system that needs both high throughput and transactional messaging?
  • How do Kafka and RocketMQ differ in message replay capabilities? What are real-world use cases for message backtracking?

风控关联:

  • 风控事件流用 Kafka(高吞吐 + Flink 集成),风控决策结果通知用 RocketMQ(事务消息保证一致性)
  • Risk control event streams use Kafka (high throughput + Flink integration), while decision result notifications use RocketMQ (transactional messages for consistency)
  • 关联 实时风控引擎

English Answer:

When choosing between Kafka, RocketMQ, and RabbitMQ, I would compare throughput, latency, reliability, ordering, transaction support, delayed messages, message replay, and operational fit. Kafka is designed for very high throughput, often at million-level TPS, with ms-level latency. Its reliability comes from replicas and ISR, it guarantees ordering within a partition, supports transactions for Kafka's exactly-once scenarios, and supports replay by offset. It is a strong fit for big data pipelines, log aggregation, and event streaming.

RocketMQ usually targets lower throughput than Kafka but still handles high traffic at the hundred-thousand TPS level. It has ms-level latency, strong reliability with synchronous flush and replication options, queue-level ordering, native transactional messages based on half messages, fixed delay levels, and message backtracking by timestamp. That makes it a good choice for e-commerce, finance, and transaction-heavy business systems.

RabbitMQ has lower throughput, commonly at the ten-thousand TPS level, but can provide very low latency at the microsecond level. It supports queue-level ordering, high reliability through mirrored or quorum-style queues depending on deployment, and delayed delivery through TTL plus DLX or a delayed-message plugin, but it does not provide native transaction messages in the same sense as RocketMQ. I would choose Kafka for high-throughput event streams, RocketMQ for transaction and delayed-message scenarios, and RabbitMQ for smaller systems that need flexible routing and very low latency. In risk control, Kafka is suitable for the real-time event stream with Flink integration, while RocketMQ is better for transaction-critical decision result notifications where consistency matters.


Q2. 如何保证消息不丢?(生产者/Broker/消费者三端)

EN: How do you ensure no message loss across producer, broker, and consumer?

难度: ★★★★★ | 出现频率: 极高(阿里、美团、字节)

Key Terms: acks=all (全副本确认), min.insync.replicas (最小同步副本数), sync flush (同步刷盘), manual ACK (手动确认), idempotent producer (幂等生产者)

答案要点:

  1. 生产者端
  2. - Kafka:acks=all(等待所有 ISR 副本确认)+ retries + enable.idempotence=true(幂等生产者) - RocketMQ:同步发送(send() 而非 sendOneway())+ 重试

  3. Broker 端
  4. - Kafka:min.insync.replicas=2 + replication.factor=3(至少 2 个副本写入成功) - RocketMQ:同步刷盘(SYNC_FLUSH)+ 主从同步复制

  5. 消费者端
  6. - 手动提交 offset / 手动 ACK,业务处理完成后再确认 - 消费幂等(去重表 / 唯一 ID)

代码示例:


消息丢失风险链路:
Producer → [网络] → Broker 写入 → [刷盘] → [副本同步] → Consumer 拉取 → [业务处理] → ACK
           ↑ 丢失点1    ↑ 丢失点2      ↑ 丢失点3      ↑ 丢失点4      ↑ 丢失点5

常见误区:

  • ❌ "设置了 acks=all 就万无一失了" → ✅ acks=all 只是生产者端保障,还需要 Broker 端同步刷盘和消费者端手动 ACK 配合,三端缺一不可
  • ❌ "Setting acks=all makes the system bulletproof" → ✅ acks=all is only a producer-side guarantee; you still need synchronous flushing on the broker and manual ACK on the consumer — all three sides must work together
  • ❌ "消费者自动提交 offset 更安全" → ✅ 自动提交可能在业务处理失败前就提交了 offset,导致消息丢失。应该手动提交,业务完成后再确认
  • ❌ "Auto-committing offsets is safer" → ✅ Auto-commit may acknowledge the offset before business processing succeeds, causing message loss. Use manual commit and confirm only after the business logic completes

延伸追问:

  • 如果 Broker 同步刷盘导致性能下降,你会怎么权衡可靠性和性能?
  • 消息不丢和消息不重复能同时保证吗?怎么做到?
  • How would you balance reliability and performance if synchronous flushing becomes a bottleneck?
  • Can you guarantee both no-loss and no-duplication at the same time? How?

风控关联:

  • 风控事件(交易、登录)消息绝不能丢,三端全部同步确认
  • Risk control events (transactions, logins) must never be lost — all three ends require synchronous confirmation
  • 关联 实时风控引擎

English Answer:

To prevent message loss, I would cover the producer, broker, and consumer sides together, because a single setting cannot protect the whole chain. On the producer side, for Kafka I would use acks=all so the producer waits for all in-sync replicas to acknowledge, configure retries, and enable the idempotent producer with enable.idempotence=true to avoid duplicate writes caused by retry. For RocketMQ, I would use synchronous send() instead of sendOneway() and configure proper retry.

On the broker side, Kafka should have a reasonable replication factor, for example replication.factor=3, and min.insync.replicas=2 so a write is considered successful only when enough replicas have persisted it. For RocketMQ, I would use synchronous flush, SYNC_FLUSH, and master-slave synchronous replication when the business requires very high reliability. These choices improve durability but may reduce throughput, so the level should match the business risk.

On the consumer side, I would disable unsafe auto-commit patterns and use manual offset commit or manual ACK. The consumer should acknowledge only after the business logic succeeds. Because retries may still produce duplicate deliveries, the consumer must also be idempotent, usually through a deduplication table, a unique message ID, Redis-based deduplication, or a business unique constraint. For transaction and login events in risk control, I would use synchronous confirmation across all three sides because losing an event can directly affect the correctness of the decision.


Q3. 消息积压了怎么处理?

EN: How do you handle message backlog in a message queue?

难度: ★★★★ | 出现频率: 高(阿里、美团、字节)

Key Terms: consumer lag (消费滞后), partition expansion (分区扩容), batch consumption (批量消费), temporary consumers (临时消费者), monitoring (监控)

答案要点:

  1. 紧急处理:增加消费者实例数(不能超过 Partition 数)→ 快速消费
  2. 临时方案:新建临时 Topic + 临时消费者转发 + 多倍消费者并行处理
  3. 批量消费max.poll.records 增大,批量处理减少网络开销
  4. 根因排查:消费慢是 CPU?IO?外部服务超时?GC?
  5. 预防:监控 Consumer Lag(Kafka Monitor / Burrow),设置告警阈值

常见误区:

  • ❌ "消息积压了就无脑加消费者实例" → ✅ 消费者实例数不能超过 Partition 数,超过的实例会空闲。需要先评估分区数,必要时扩分区或用临时 Topic 转发
  • ❌ "Just throw more consumer instances at the backlog" → ✅ Consumer count cannot exceed partition count — excess instances sit idle. Evaluate partitions first, then expand or use temporary topic forwarding
  • ❌ "积压只是消费者的问题" → ✅ 积压可能是生产端突增、消费者逻辑慢、外部服务超时、GC 停顿等多种原因,需要根因排查
  • ❌ "Backlog is always a consumer problem" → ✅ Backlog can stem from producer surges, slow consumer logic, external service timeouts, or GC pauses — root cause analysis is essential

延伸追问:

  • 如果消费者扩容后仍然积压,下一步你会怎么处理?
  • 怎么设计监控体系来提前发现积压风险,而不是等到业务告警?
  • If adding more consumers doesn't resolve the backlog, what is your next step?
  • How would you design a monitoring system to catch backlog risks early, before business alerts fire?

风控关联:

  • 风控事件积压意味着实时决策延迟升高。紧急方案:积压事件走轻量规则引擎快速过滤,高风险转人工
  • Backlogged risk events mean elevated real-time decision latency. Emergency plan: route backlogged events through a lightweight rule engine for fast filtering, escalate high-risk cases to manual review
  • 关联 实时风控引擎

English Answer:

When a message backlog happens, I would first separate emergency mitigation from root-cause analysis. For emergency handling, I would increase the number of consumer instances, but only up to the number of partitions, because extra consumers in the same consumer group will stay idle if there are no partitions assigned to them. If the existing partition count is too small, I would consider expanding partitions or using a temporary topic.

A common temporary solution is to create a new topic with more partitions, start temporary consumers to forward the backlog into that topic, and then use many more consumers to process it in parallel. I would also tune batch consumption, for example increasing max.poll.records in Kafka, so each poll handles more messages and reduces network overhead, as long as the processing time still stays within the consumer timeout limits.

After stabilizing the system, I would investigate why the backlog happened. The cause may be a producer traffic spike, slow consumer business logic, CPU saturation, IO bottlenecks, external service timeout, GC pauses, or downstream rate limits. For prevention, I would monitor consumer lag with tools such as Kafka Monitor or Burrow, configure alert thresholds, and connect the alert to business metrics. In risk control, backlog means real-time decisions become delayed, so an emergency fallback can route backlogged events through lightweight rules first and escalate high-risk cases to manual review.


Q4. Kafka 高性能的原因是什么?

EN: What makes Kafka so performant?

难度: ★★★★ | 出现频率: 高(阿里、美团、字节)

Key Terms: sequential write (顺序写), zero-copy (零拷贝), sendfile (系统调用), page cache (页缓存), batch compression (批量压缩), partition parallelism (分区并行)

答案要点:

  1. 顺序写(Sequential Write):追加写入磁盘,速度接近内存(600MB/s vs 随机写 100KB/s)
  2. 零拷贝(Zero-Copy)sendfile() 系统调用,数据从磁盘直接到网卡,跳过用户态拷贝
  3. 页缓存(Page Cache):利用 OS 页缓存,写入先到内存,异步刷盘
  4. 批量+压缩:Producer 批量发送 + gzip/lz4 压缩,减少网络 IO
  5. 分区并行:Topic 多 Partition 并行读写,水平扩展
  6. 稀疏索引:offset 索引,快速定位消息位置

常见误区:

  • ❌ "磁盘 IO 一定是性能瓶颈,所以 Kafka 必须全部放内存" → ✅ Kafka 利用顺序写磁盘(600MB/s)远快于随机写(100KB/s),配合 Page Cache,磁盘性能已接近内存,不需要全部放内存
  • ❌ "Disk I/O is always the bottleneck, so Kafka must keep everything in memory" → ✅ Kafka exploits sequential disk writes (600MB/s), far faster than random writes (100KB/s), combined with Page Cache — disk performance approaches memory without requiring everything in RAM
  • ❌ "零拷贝就是不用拷贝数据" → ✅ 零拷贝是减少 CPU 参与的内存拷贝次数(从 4 次 reduce 到 2 次),数据仍然需要从磁盘到网卡,只是跳过了用户态的中转
  • ❌ "Zero-copy means no data copying at all" → ✅ Zero-copy reduces CPU-involved memory copies from 4 to 2; data still travels from disk to NIC, but bypasses user-space buffering

延伸追问:

  • 传统的数据传输流程是怎样的?零拷贝具体省掉了哪几次拷贝?
  • Kafka 的 Page Cache 和 JVM 堆内缓存相比有什么优势?
  • Walk through the traditional data transfer path. Which copies does zero-copy eliminate?
  • What advantages does Kafka's Page Cache have over in-heap JVM caching?

风控关联:

  • 风控实时事件流依赖 Kafka 高吞吐能力,保证海量交易事件快速入队和消费
  • Real-time risk control event streams rely on Kafka's high throughput to ensure massive transaction events are enqueued and consumed rapidly
  • 关联 实时风控引擎

English Answer:

Kafka's performance comes from several design choices working together. First, Kafka writes messages sequentially to append-only log files. Sequential disk writes are much faster than random writes and can approach memory-like throughput in practice, so Kafka does not need to keep all messages in JVM memory.

Second, Kafka uses zero-copy transfer, typically through sendfile(), when sending data from disk to the network. In the traditional path, data is copied between disk, kernel space, user space, and socket buffers. Zero-copy reduces CPU-involved memory copies and avoids unnecessary user-space buffering, so the broker can serve consumers with much lower CPU overhead.

Third, Kafka relies heavily on the operating system page cache. Writes first hit memory and are flushed asynchronously by the OS, and reads can often be served directly from cache. Compared with maintaining a large JVM heap cache, page cache avoids GC pressure and uses the OS's mature cache management.

Fourth, Kafka improves throughput through producer batching and compression such as gzip or lz4, which reduce request count and network IO. Fifth, topics are split into multiple partitions, so producers and consumers can read and write in parallel and scale horizontally. Finally, Kafka uses sparse offset indexes to locate messages efficiently without indexing every message. For risk control event streams, these features allow a large volume of transaction events to be ingested and consumed quickly.


Q5. 顺序消息怎么实现?

EN: How do you implement ordered message delivery?

难度: ★★★★ | 出现频率: 高(阿里、美团、字节)

Key Terms: message routing key (消息路由键), partition key (分区键), single partition ordering (单分区有序), single consumer thread (单消费线程)

答案要点:

  1. 全局有序:整个 Topic 只有一个 Partition(牺牲并行性,不推荐)
  2. 局部有序(推荐):相同业务 key 的消息路由到同一 Partition
  3. - Kafka:指定 partition key(如 orderId),相同 key 哈希到同一 Partition - RocketMQ:MessageQueueSelector 选择队列

  4. 消费端保证:同一 Partition 只有一个消费者线程处理,或用内存队列保证顺序

代码示例:


// Kafka 顺序消息:相同 orderId 的消息发到同一 Partition
ProducerRecord<String, String> record = new ProducerRecord<>(
    "risk-events",
    orderId,  // key → hash to same partition
    eventJson
);
producer.send(record);

常见误区:

  • ❌ "多 Partition 也能保证全局有序" → ✅ 多 Partition 只能保证分区内有序,无法保证全局有序。全局有序只能用单 Partition,但会牺牲并行性
  • ❌ "Multiple partitions can still guarantee global ordering" → ✅ Multiple partitions only guarantee per-partition ordering. Global ordering requires a single partition, which sacrifices parallelism
  • ❌ "只要发送端保证顺序就行" → ✅ 发送端保证同 key 到同 Partition 只是第一步,消费端也需要保证单线程消费或内存队列排序,否则仍然乱序
  • ❌ "Ordering is the producer's responsibility alone" → ✅ Routing same-key messages to the same partition is only step one; the consumer must also use a single thread or in-memory queue ordering, otherwise messages still arrive out of order

延伸追问:

  • 如果 Partition 数量发生变化(扩容),原有的顺序消息会受影响吗?怎么处理?
  • 顺序消息场景下,某条消息消费失败会阻塞后续消息吗?怎么解决?
  • If the partition count changes during scale-up, will existing ordered messages be affected? How do you handle this?
  • In an ordered consumption scenario, does a single failed message block all subsequent messages? How do you resolve this?

风控关联:

  • 同一笔交易的风控事件(请求→决策→通知)必须有序。用 transactionId 作为 partition key
  • Risk control events for the same transaction (request → decision → notification) must be ordered. We use transactionId as the partition key
  • 关联 实时风控引擎

English Answer:

Ordered messages can be implemented at two levels. Global ordering means the entire topic has only one partition or one queue, so all messages are consumed in the exact order they are produced. This is simple but sacrifices parallelism and is usually not recommended for high-throughput systems.

The recommended approach is local or key-based ordering. Messages with the same business key must be routed to the same partition or queue. In Kafka, the producer sets a partition key such as orderId or transactionId, and messages with the same key are hashed to the same partition. In RocketMQ, the producer can use MessageQueueSelector to choose the target queue based on the business key.

The consumer side must also preserve ordering. For the same partition, only one consumer in a consumer group can consume it at a time, but the application must avoid handing messages from that partition to multiple worker threads in a way that breaks order. If asynchronous processing is needed, the consumer can use per-key in-memory queues or single-thread execution per partition. In risk control, events for the same transaction, such as request, decision, and notification, should use transactionId as the partition key so they are processed in sequence.


Q6. RocketMQ 事务消息原理?

EN: How does RocketMQ implement transaction messages?

难度: ★★★★ | 出现频率: 高(阿里、美团、蚂蚁)

Key Terms: half message (半消息), local transaction (本地事务), commit/rollback (提交/回滚), transaction check (事务回查), back-check (回查机制)

答案要点:

  1. Producer 发送半消息(Half Message)到 Broker,对消费者不可见
  2. Broker 存储半消息并返回确认
  3. Producer 执行本地事务
  4. 根据本地事务结果发送 Commit(消息可见)或 Rollback(消息删除)
  5. 回查机制:如果 Broker 长时间未收到二次确认 → 回查(Check)Producer 本地事务状态 → 根据结果 Commit/Rollback

常见误区:

  • ❌ "事务消息就是分布式事务的完美解决方案" → ✅ 事务消息只保证本地事务与消息发送的最终一致性,不保证下游消费者的处理结果。它是一种最终一致性方案,不是强一致性
  • ❌ "Transactional messages are a silver bullet for distributed transactions" → ✅ They only guarantee eventual consistency between the local transaction and message delivery, not the downstream consumer's outcome — this is an eventual consistency pattern, not strong consistency
  • ❌ "半消息会阻塞正常消息的消费" → ✅ 半消息存储在特殊的内部 Topic 中,对消费者完全不可见,不会影响正常消息的消费
  • ❌ "Half messages block normal message consumption" → ✅ Half messages are stored in a special internal topic and are completely invisible to consumers — they do not interfere with normal message processing

延伸追问:

  • 事务消息的回查机制如果 Producer 已下线,消息会怎么处理?
  • 事务消息和 Kafka 的事务 API(exactly-once)有什么本质区别?
  • What happens to a half message if the Producer is offline when the broker triggers a transaction check?
  • What is the fundamental difference between RocketMQ transactional messages and Kafka's exactly-once transaction API?

风控关联:

  • 风控决策结果与交易处理用事务消息保证一致性:决策通过 → 提交事务消息 → 下游处理
  • Transactional messages ensure consistency between risk control decisions and transaction processing: decision approved → commit transactional message → downstream processing
  • 关联 实时风控引擎

English Answer:

RocketMQ transactional messages are designed to guarantee eventual consistency between a producer's local transaction and message delivery. The first step is that the producer sends a half message to the broker. The broker stores this half message and returns an acknowledgment, but the message is invisible to normal consumers at this stage.

After the half message is stored, the producer executes its local transaction, such as updating an order or recording a risk decision. If the local transaction succeeds, the producer sends a Commit request to the broker, and the broker makes the message visible to consumers. If the local transaction fails, the producer sends a Rollback request, and the broker deletes or discards the half message.

If the broker does not receive the second confirmation for a long time, it triggers a transaction check. The broker calls back to the producer to query the local transaction status, and then decides whether to commit or roll back the message based on that status. This mechanism is not a strong distributed transaction and does not guarantee the downstream consumer's processing result. It only guarantees eventual consistency between the local transaction and the message becoming visible. In risk control, it can be used to keep a risk decision record and the downstream decision notification consistent.


Q7. 消息幂等怎么实现?

EN: How do you achieve idempotent message consumption?

难度: ★★★★ | 出现频率: 高(阿里、美团、字节)

Key Terms: idempotency key (幂等键), dedup table (去重表), Redis SETNX (Redis不存在则设置), database unique constraint (数据库唯一约束), state machine (状态机)

答案要点:

  1. 去重表:消费前用消息 ID(全局唯一)写入去重表,写入成功才处理
  2. Redis SETNXSET messageId 1 NX EX 3600,设置成功才处理
  3. 数据库唯一约束:业务表用唯一索引防重复
  4. 状态机:订单状态只能单向流转,重复消费会被状态校验拦截

常见误区:

  • ❌ "Kafka 有 exactly-once 语义就不需要消费端幂等了" → ✅ Kafka 的 exactly-once 只保证 Kafka 内部(消费 offset + 生产消息)的原子性,涉及外部系统(DB/Redis)仍需消费端自行保证幂等
  • ❌ "Kafka's exactly-once semantics eliminate the need for consumer-side idempotency" → ✅ Kafka's exactly-once only guarantees atomicity within Kafka (offset commit + message produce). When external systems (DB/Redis) are involved, consumer-side idempotency is still required
  • ❌ "去重表用完就可以删了" → ✅ 去重表的记录需要保留足够长时间(至少大于消息重试窗口期),否则删除后重复消息可能再次被消费
  • ❌ "Dedup table records can be deleted right after use" → ✅ Dedup records must be retained long enough (at least longer than the retry window), otherwise deleted records may allow duplicate consumption

延伸追问:

  • 去重表方案在高并发下会不会成为瓶颈?怎么优化?
  • 如果用 Redis SETNX 做幂等,Redis 挂了怎么办?
  • Can a dedup table become a bottleneck under high concurrency? How would you optimize it?
  • What happens if Redis goes down while you're using SETNX for idempotency?

风控关联:

  • 风控决策结果的消费幂等:用 transactionId + decisionVersion 作为去重 key
  • Risk control decision consumption idempotency: use transactionId + decisionVersion as the dedup key
  • 关联 实时风控引擎

English Answer:

Idempotent consumption means that even if the same message is delivered more than once, the final business result is the same as processing it once. A common approach is a deduplication table. Before processing, the consumer inserts a globally unique message ID into the table. If the insert succeeds, it processes the message; if the insert fails because the ID already exists, the message is treated as a duplicate and skipped.

For lightweight scenarios, Redis SETNX can be used, for example setting messageId with NX and an expiration time. Only the consumer that successfully sets the key proceeds with processing. This is fast, but the expiration time must be longer than the retry window, and Redis availability must be considered.

Another approach is to use database unique constraints directly on business tables. For example, a payment result table can have a unique index on transactionId, so duplicate inserts fail naturally. A fourth approach is to model business state as a state machine. If an order or risk decision can only move forward through valid states, duplicate or stale messages will be rejected by state validation.

Kafka's exactly-once semantics do not remove the need for consumer-side idempotency when external systems such as DB or Redis are involved. In risk control, I would use transactionId + decisionVersion as the idempotency key so that repeated delivery of the same decision does not trigger duplicate downstream actions.


Q8. Kafka exactly-once 语义怎么实现?

EN: How does Kafka achieve exactly-once semantics?

难度: ★★★★★ | 出现频率: 中高(字节、蚂蚁、美团)

Key Terms: idempotent producer (幂等生产者), transactional API (事务API), consumer offset commit + output to Kafka (消费者偏移提交+生产到Kafka), isolation.level=read_committed (隔离级别=读已提交)

答案要点:

  1. 幂等生产者enable.idempotence=true):Producer 分配 PID + Sequence Number,Broker 检测重复
  2. 事务 APIbeginTransaction() → send → sendOffsetsToTransaction()commitTransaction()。将消费 offset 提交和生产消息放在同一个事务中
  3. 限制:只保证 Kafka 内部的 exactly-once,外部系统(DB/Redis)需要自行保证幂等

常见误区:

  • ❌ "Kafka exactly-once 能保证端到端的精确一次" → ✅ Kafka exactly-once 只保证 Kafka 集群内部(从消费到生产)的精确一次,涉及外部系统仍需自行保证幂等
  • ❌ "Kafka exactly-once guarantees end-to-end exactly-once processing" → ✅ Kafka exactly-once only guarantees exactly-once within the Kafka cluster (consume to produce). External systems still require consumer-side idempotency
  • ❌ "开启了幂等生产者就不需要事务 API 了" → ✅ 幂等生产者只保证单 Partition 的去重,跨多 Partition 的原子写入必须用事务 API
  • ❌ "Enabling the idempotent producer eliminates the need for the transaction API" → ✅ The idempotent producer only deduplicates within a single partition; atomic writes across multiple partitions require the transaction API

延伸追问:

  • Kafka 事务 API 的性能开销有多大?生产环境怎么权衡?
  • Consume-Transform-Produce 模式下,如果中间步骤调用了外部 API,怎么保证一致性?
  • What is the performance overhead of Kafka's transaction API? How do you balance it in production?
  • In a Consume-Transform-Produce pattern, if the transform step calls an external API, how do you maintain consistency?

风控关联:

  • 风控流处理中,从事件消费到决策结果生产的 exactly-once 保障,避免重复风控或遗漏
  • In risk control stream processing, exactly-once semantics from event consumption to decision result production prevents duplicate risk evaluations or missed events
  • 关联 实时风控引擎

English Answer:

Kafka implements exactly-once semantics through the idempotent producer and the transactional API. With enable.idempotence=true, Kafka assigns a Producer ID and sequence numbers to producer messages. The broker uses these sequence numbers to detect retry duplicates and discard repeated messages, so the producer can safely retry without creating duplicates within a partition.

For consume-transform-produce scenarios, Kafka uses the transactional API. The producer starts a transaction with beginTransaction(), sends output records, sends the consumed offsets into the same transaction with sendOffsetsToTransaction(), and then calls commitTransaction(). This makes the offset commit and the output messages atomic inside Kafka. If the transaction aborts, consumers using isolation.level=read_committed will not read uncommitted output records.

The important limitation is that Kafka's exactly-once guarantee is scoped to Kafka itself, mainly the pipeline from consuming Kafka records to producing Kafka records. If the processing step writes to MySQL, Redis, or calls an external API, Kafka cannot make those external side effects exactly-once. In those cases, the application still needs idempotency keys, unique constraints, outbox patterns, or compensation logic. In risk control stream processing, Kafka exactly-once can prevent duplicate or missing decision result messages within the Kafka pipeline, but external decision storage still needs its own idempotency design.


Q9. 消费者 Rebalance 是什么?会导致什么问题?

EN: What is consumer rebalancing? What problems can it cause?

难度: ★★★ | 出现频率: 中高(阿里、美团)

Key Terms: rebalance (重平衡), consumer group coordinator (消费者组协调器), sticky assignor (粘性分配器), session.timeout (会话超时), heartbeat (心跳)

答案要点:

  1. 触发条件:消费者加入/离开 Group、订阅 Topic 变化、Partition 数量变化
  2. 问题:Rebalance 期间所有消费者停止消费(Stop The World),频繁 Rebalance 导致消费延迟
  3. 避免频繁 Rebalance
  4. - session.timeout.ms 适当调大(如 25s) - heartbeat.interval.ms 调小(如 8s) - max.poll.interval.ms 调大(处理时间长的场景) - 使用 StickyAssignor(尽量保持原有分配不变)

常见误区:

  • ❌ "Rebalance 只是短暂的停顿,影响不大" → ✅ 在大规模消费者组中,Rebalance 可能持续数分钟,期间所有消费者停止消费,导致严重的消息积压
  • ❌ "Rebalance is just a brief pause — no big deal" → ✅ In large consumer groups, rebalancing can last minutes, during which all consumers stop processing, causing severe message backlog
  • ❌ "消费者处理慢就会触发 Rebalance" → ✅ 不是处理慢本身触发 Rebalance,而是处理时间超过 max.poll.interval.ms 导致被踢出 Group 才触发。调大该参数即可避免
  • ❌ "Slow consumer processing directly triggers rebalance" → ✅ It's not slowness per se — rebalance is triggered when processing time exceeds max.poll.interval.ms and the consumer is kicked out. Increasing this parameter avoids the issue

延伸追问:

  • Kafka 社区在 Rebalance 机制上有哪些改进?(如 KIP-429 CooperativeStickyAssignor)
  • 你怎么排查和定位线上频繁 Rebalance 的原因?
  • What improvements has the Kafka community made to the rebalance mechanism? (e.g., KIP-429 CooperativeStickyAssignor)
  • How do you diagnose and pinpoint the root cause of frequent rebalances in production?

风控关联:

  • 风控消费者频繁 Rebalance 会导致事件处理停顿,影响实时决策的时效性。需优化参数和监控
  • Frequent rebalances in risk control consumers cause event processing pauses, degrading real-time decision timeliness. Parameter tuning and monitoring are essential
  • 关联 实时风控引擎

English Answer:

Consumer rebalance is the process of reassigning topic partitions among consumers in the same consumer group. It is triggered when a consumer joins or leaves the group, when subscribed topics change, or when the number of partitions changes. The group coordinator manages this process and assigns partitions according to the configured assignor.

The main problem is that traditional rebalance can cause a Stop-The-World pause for the consumer group. During the rebalance window, consumers stop consuming, and in large groups this may last long enough to create visible consumer lag or message backlog. Frequent rebalance is especially harmful because the system repeatedly pauses, revokes partitions, and rebuilds local state.

To reduce unnecessary rebalance, I would tune session.timeout.ms to a reasonable larger value so transient heartbeat delays do not immediately remove a consumer, set heartbeat.interval.ms lower so heartbeats are sent more frequently, and increase max.poll.interval.ms for workloads where message processing may take longer. I would also use StickyAssignor or cooperative sticky assignment where available, because it tries to keep existing partition ownership stable and reduces partition movement. In risk control, frequent rebalance can pause event processing and hurt real-time decision latency, so rebalance metrics, lag, and consumer heartbeat health should be monitored.


Q10. 延迟消息怎么实现?

EN: How do you implement delayed message delivery?

难度: ★★★ | 出现频率: 中高(美团、字节)

Key Terms: delay level (延迟等级), TTL + DLX (存活时间+死信交换), time wheel (时间轮), ZSet (有序集合), scheduled task (定时任务)

答案要点:

  1. RocketMQ:原生支持 18 个延迟等级(1s~2h),setDelayTimeLevel(3)
  2. Kafka:不原生支持。方案:① 时间轮 + 定时转发 ② 外部调度(XXL-Job)③ 改用 RocketMQ
  3. RabbitMQ:TTL + 死信队列(DLX),或插件 rabbitmq-delayed-message-exchange
  4. Redis:ZSet(score = 执行时间),定时扫描

常见误区:

  • ❌ "RabbitMQ 的 TTL + DLX 方案和原生延迟消息一样好用" → ✅ TTL + DLX 方案存在消息堆积时延迟不准的问题(TTL 最短的消息先过期),且配置复杂。RabbitMQ 社区插件是更好的选择
  • ❌ "RabbitMQ's TTL + DLX approach works just as well as native delayed messages" → ✅ TTL + DLX suffers from inaccurate delays under load (shortest-TTL messages expire first) and requires complex configuration. The RabbitMQ delayed message plugin is a better option
  • ❌ "Kafka 完全不支持延迟消息,只能换 RocketMQ" → ✅ 可以通过时间轮 + 定时转发 Topic 的方案在 Kafka 上实现延迟消息,只是需要额外开发
  • ❌ "Kafka cannot handle delayed messages at all — you must switch to RocketMQ" → ✅ You can implement delayed delivery on Kafka using a time-wheel + scheduled topic-forwarding approach, though it requires additional development

延伸追问:

  • RocketMQ 的延迟等级是固定的,如果需要任意时间延迟怎么办?
  • 用 Redis ZSet 实现延迟队列,怎么保证消息不丢和高可用?
  • RocketMQ's delay levels are fixed. What if you need arbitrary delay durations?
  • How do you ensure message durability and high availability when implementing a delay queue with Redis ZSet?

风控关联:

  • 风控决策后的延迟操作(如"30 分钟后复查该用户")用延迟消息实现
  • Post-decision delayed actions in risk control (e.g., "re-evaluate this user in 30 minutes") are implemented via delayed messages
  • 关联 实时风控引擎

English Answer:

Delayed message implementation depends on the middleware. RocketMQ provides native delayed messages with fixed delay levels, traditionally 18 levels from seconds to hours. The producer sets a delay level, such as setDelayTimeLevel(3), and the broker delivers the message when that level expires. The limitation is that the levels are fixed, so arbitrary delay durations may require an additional scheduling layer.

Kafka does not provide native delayed messages. Common solutions include a time wheel plus scheduled forwarding, where delayed messages are first written to delay topics and then forwarded to the real topic when due; using an external scheduler such as XXL-Job; or choosing RocketMQ when delayed delivery is a core requirement. These Kafka-based solutions work, but they add development and operational complexity.

RabbitMQ can implement delayed delivery through TTL plus a dead letter exchange. A message expires in one queue and is routed to the real queue through DLX. However, this approach can have inaccurate delays when messages pile up and is more complex to configure. The rabbitmq-delayed-message-exchange plugin is often easier when plugin usage is acceptable. Redis ZSet is another lightweight delay queue design: the score is the execution timestamp, and scheduled workers scan due messages. For risk control, delayed messages are useful for follow-up actions, such as re-evaluating a user 30 minutes after a suspicious decision.


关联

  • Redis — 延迟队列的 Redis ZSet 方案
  • 分布式系统 — 消息队列是分布式系统的核心基础设施
  • Spring — Spring Kafka / Spring Cloud Stream 整合
  • 实时风控引擎 — 风控事件流的核心管道