使用 Spring for Apache Kafka
本节详细阐述影响使用 Spring for Apache Kafka 的各种关注点。如需快速但较粗略的介绍,请参阅 Quick Tour。
章节小结
连接到 Kafka
KafkaAdmin — 参见配置主题
配置主题
如果你在应用程序上下文中定义了一个 KafkaAdmin bean,它可以自动向代理添加主题。为此, 你可以为每个主题向应用程序上下文添加一个 NewTopic @Bean。2.3 版本引入了一个新类 TopicBuilder,使此类 bean 的创建更加方便。以下示例展示了如何做到这一点:
发送消息
本节介绍如何发送消息。
接受消息
19 个项目
监听容器属性
ackCount
动态创建容器
有若干技术可用于在运行时创建监听容器。本节探讨其中一些技术。
应用程序事件
以下 Spring 应用程序事件由监听容器及其消费者发布:
主题/分区初始偏移量
有若干种方法可以为分区设置初始偏移量。
Seek 到特定偏移量
为了进行 seek,你的监听器必须实现 ConsumerSeekAware,它具有以下方法:
容器工厂
如 @KafkaListener 注解一节所述, ConcurrentKafkaListenerContainerFactory 用于为注解方法创建容器。
线程安全
使用并发消息监听容器时,单个监听器实例会在所有消费者线程上被调用。因此,监听器需要是 线程安全的,最好使用无状态监听器。如果无法使监听器线程安全,或者添加同步会显著降低并发 带来的收益,你可以采用以下几种技术之一:
监控
从 2.3 版本开始,如果 classpath 上检测到 Micrometer,且应用程序上下文中存在单个 MeterRegistry,监听容器将自动为监听器创建并更新 Micrometer Timer。可以通过将 ContainerProperty 的 micrometerEnabled 设置为 false 来禁用这些计时器。
事务
本节描述 Spring for Apache Kafka 如何支持事务。
恰好一次语义
你可以为监听容器提供一个 KafkaAwareTransactionManager 实例。如此配置后,容器在调用 监听器之前开启一个事务。监听器执行的任何 KafkaTemplate 操作都参与该事务。如果监听器 成功处理了记录(在使用 BatchMessageListener 时为多条记录),容器会在事务管理器提交 事务之前,通过 producer.sendOffsetsToTransaction() 将偏移量发送到事务中。如果监听器 抛出异常,事务将回滚,消费者被重新定位,以便在下一次轮询时取回被回滚的记录。更多信息 以及对反复失败记录的处理,请参见回滚后处理器。
将 Spring Bean 装配进生产者/消费者拦截器
Apache Kafka 提供了向生产者和消费者添加拦截器的机制。这些对象由 Kafka 而非 Spring 管理,因此常规的 Spring 依赖注入无法用于装配所依赖的 Spring Bean。不过,你可以使用 拦截器的 config() 方法手动装配这些依赖。以下 Spring Boot 应用展示了如何通过覆盖 Spring Boot 的默认工厂,将某个依赖 bean 添加到配置属性中来做到这一点。
在 Spring 中管理的生产者拦截器
从 3.0.0 版本开始,对于生产者拦截器,你可以让 Spring 直接将其作为 bean 管理,而不是 向 Apache Kafka 生产者配置提供拦截器的类名。如果你采用这种方式,则需要在 KafkaTemplate 上设置这个生产者拦截器。以下示例使用与上文相同的 MyProducerInterceptor,但改为不使用内部配置属性。
暂停和恢复监听容器
2.1.3 版本向监听容器添加了 pause() 和 resume() 方法。此前,你可以在 ConsumerAwareMessageListener 内暂停消费者,并通过监听 ListenerContainerIdleEvent 来恢复它,该事件提供了对 Consumer 对象的访问。虽然你可以使用事件监听器在空闲容器中 暂停消费者,但在某些情况下这并不是线程安全的,因为无法保证事件监听器在消费者线程上被 调用。要安全地暂停和恢复消费者,你应使用监听容器上的 pause 和 resume 方法。 pause() 在下一次 poll() 之前立即生效;resume() 在当前 poll() 返回之后立即生效。当 容器被暂停时,它会继续对消费者进行 poll(),如果使用了消费者组管理则避免再均衡,但不会 检索任何记录。更多信息请参阅 Kafka 文档。
在监听容器上暂停和恢复分区
从 2.7 版本开始,你可以通过监听容器中的 pausePartition(TopicPartition topicPartition) 和 resumePartition(TopicPartition topicPartition) 方法,暂停和 恢复分配给该消费者的特定分区的消费。暂停和恢复分别发生在 poll() 之前和之后,类似于 pause() 和 resume() 方法。如果已请求暂停某个分区,isPartitionPauseRequested() 方法返回 true。如果该分区已实际被暂停,isPartitionPaused() 方法返回 true。
序列化、反序列化与消息转换
Apache Kafka 提供了一个高级 API,用于序列化和反序列化记录值及其键。 它以 org.apache.kafka.common.serialization.Serializer<T> 与 org.apache.kafka.common.serialization.Deserializer<T> 抽象的形式存在, 并附带一些内置实现。同时,我们可以通过使用 Producer 或 Consumer 配置属性来指定序列化器和反序列化器类。以下示例展示了如何做到这一点:
消息头
0.11.0.0 客户端引入了对消息中头(header)的支持。从 2.0 版本开始,Spring for Apache Kafka 支持在这些头与 spring-messaging MessageHeaders 之间进行双向映射。
空载荷与 'Tombstone' 记录的日志压缩
当你使用日志压缩时,可以发送和接收载荷为 null 的消息,以标识某个键的删除。
处理异常
本节描述在使用 Spring for Apache Kafka 时如何处理可能出现的各种异常。
JAAS 与 Kerberos
从 2.0 版本开始,新增了 KafkaJaasLoginModuleInitializer 类以协助 Kerberos 配置。你可以将这个带有所需配置的 bean 添加到应用程序上下文中。以下示例配置了这样 一个 bean:
Kafka 队列(共享消费者)
自 4.0 版本起,Spring for Apache Kafka 通过共享消费者(share consumer)为 Kafka 队列提供支持,实现了 KIP-932(Queues for Kafka)。截至 Spring for Apache Kafka 4.1,以 Apache Kafka 4.2 为底座,共享消费者 已晋升为完整的生产级支持。