如果需要精确控制消息处理后的偏移量,如下配置:
yaml
kafka:
bootstrap-servers: com.kafka1:9092,com.kafka2:9092,com.kafka3:9092
consumer:
group-id: eorder-sync-consumer-group
enable-auto-commit: false # 关闭自动提交
auto-commit-interval: 1000
max-poll-records: 500
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
listener:
ack-mode: manual_immediate # 此时手动确认才会真正生效
concurrency: 12
type: batch
log-container-config: true
-
偏移量提交行为
-
1. 自动提交被禁用
-
- enable-auto-commit: false 完全禁用了Kafka消费者的自动提交机制
- 即使有
auto-commit-interval: 1000配置,也不会生效
-
2. 缺少确认模式配置
- 由于没有配置
ack-mode,Spring Kafka会使用默认的确认模式: - 默认ack-mode行为:
-
- 对于 record 监听器(非batch):默认是
AckMode.BATCH - 对于 batch 监听器(配置了
type: batch):默认行为是在每批消息处理完成后自动提交偏移量
- 对于 record 监听器(非batch):默认是
对比说明
| 配置 | 提交行为 |
|---|---|
enable-auto-commit: true | Kafka客户端自动提交,与消息处理无关 |
enable-auto-commit: false + 无ack-mode | Spring容器批量处理完成后提交 |
enable-auto-commit: false + ack-mode: manual_immediate | 完全手动控制,需要代码中确认 |
Spring Kafka Listener Ack-Mode 详细解析
ack-mode 是 Spring Kafka 中控制消费者偏移量提交行为的重要配置,它决定了消息确认和偏移量提交的时机和方式。
1. ack-mode 的六种模式
1.1 RECORD(每记录确认)
yaml
listener:
ack-mode: record
行为特点:
- 每条消息处理成功后立即提交偏移量
- 提交频率高,性能开销相对较大
- 确保每条消息至少被处理一次
- 如果处理失败,只有当前消息会重试
适用场景:
- 消息处理重要性高,不能丢失
- 消息处理时间较长,需要及时提交
- 消息之间有独立性
1.2 BATCH(批量确认)- 默认模式
yaml
listener:
ack-mode: batch
行为特点:
- 每批消息全部处理成功后一次性提交偏移量
- 提交频率低,性能较好
- 如果批处理中某条消息失败,整批消息都会重试
- 与
enable-auto-commit: false配合使用
适用场景:
- 批量处理消息的场景
- 追求高性能的场景
- 消息处理具有幂等性
1.3 TIME(时间间隔确认)
yaml
listener:
ack-mode: time
ack-time: 5000 # 5秒提交一次
行为特点:
- 按照固定时间间隔提交偏移量
- 与消息处理进度无关
- 可能提交已处理但未确认的消息偏移量
适用场景:
- 对实时性要求不高的场景
- 消息处理时间不固定的场景
1.4 COUNT(计数确认)
yaml
listener:
ack-mode: count
ack-count: 100 # 每100条消息提交一次
行为特点:
- 累积处理指定数量的消息后提交偏移量
- 与时间无关,只与消息数量相关
适用场景:
- 消息处理速率稳定的场景
- 需要控制提交频率的场景
1.5 COUNT_TIME(计数或时间确认)
yaml
listener:
ack-mode: count_time
ack-time: 5000 # 5秒
ack-count: 100 # 或100条消息
行为特点:
- 满足计数或时间条件中的任意一个就提交
- 先达到哪个条件就按哪个提交
适用场景:
- 需要灵活控制提交策略的场景
1.6 MANUAL(手动确认)
yaml
listener:
ack-mode: manual
行为特点:
- 需要在代码中显式调用
acknowledge()方法 - 提供最精确的控制
- 可以控制单条消息或整批消息的确认
代码示例:
java
@KafkaListener(topics = "myTopic")
public void listen(ConsumerRecord<String, String> record,
Acknowledgment ack) {
try {
// 处理消息
processMessage(record);
// 手动确认
ack.acknowledge();
} catch (Exception e) {
// 不确认,消息会重试
}
}
1.7 MANUAL_IMMEDIATE(手动立即确认)
yaml
listener:
ack-mode: manual_immediate
行为特点:
- 与 MANUAL 类似,但确认后立即提交偏移量
- 比 MANUAL 模式的响应更快
2. ack-mode 与相关配置的关系
2.1 与 enable-auto-commit 的关系
yaml
consumer:
enable-auto-commit: false # 必须为false,ack-mode才生效
listener:
ack-mode: batch # 此时ack-mode控制提交行为
2.2 与 type: batch 的关系
yaml
listener:
ack-mode: batch
type: batch # 批量监听模式
- 在批量模式下,ack-mode 针对的是整批消息
- 提交的是整批消息的最大偏移量
3. 不同 ack-mode 的提交时机对比
| ack-mode | 提交时机 | 性能 | 可靠性 | 使用复杂度 |
|---|---|---|---|---|
| RECORD | 每条消息处理后 | 较低 | 最高 | 简单 |
| BATCH | 每批消息处理后 | 高 | 高 | 简单 |
| TIME | 固定时间间隔 | 中 | 中 | 简单 |
| COUNT | 固定数量后 | 中 | 中 | 简单 |
| COUNT_TIME | 计数或时间 | 中 | 中 | 中等 |
| MANUAL | 代码控制 | 可调节 | 最高 | 复杂 |
| MANUAL_IMMEDIATE | 代码控制立即提交 | 可调节 | 最高 | 复杂 |
4. 实际应用建议
4.1 高可靠性场景
yaml
listener:
ack-mode: record
concurrency: 3 # 降低并发提高可靠性
4.2 高性能场景
yaml
listener:
ack-mode: batch
concurrency: 12
type: batch
4.3 精确控制场景
yaml
listener:
ack-mode: manual_immediate
concurrency: 6
5. 注意事项
- 确保 enable-auto-commit: false,否则 ack-mode 不生效
- 合理设置 max-poll-records,避免批量过大导致内存问题
- 考虑消息幂等性,特别是在 BATCH 模式下
- 监控提交延迟,确保偏移量及时提交
通过合理配置 ack-mode,可以在性能、可靠性和复杂度之间找到最佳平衡点。