在我们的项目中,我们需要通过许多线程定期从第三方获取数据,然后将其推送到Kafka。而且,如果此时Kafka服务器不可用,则应终止该流,应将获取的数据丢失并在下一次计划执行期间重新获取。另外,还需要使用事务管理,因为我们需要将这批消息发送到Kafka的不同主题。如果没有发送一条消息,则所有其他消息都应回滚。
如果Kafka Server不可用,我们会遇到终止执行的问题。禁用交易管理后,一切正常,我们得到
org.apache.kafka.common.errors.TimeoutException: Failed to update metadata after 60000 ms.
但是在启用事务管理的情况下,Kafka生产者尝试无限访问服务器,并且所有发起将消息推送到Kafka的线程都将停留。我们尝试了不同的设置,以使其在一段时间不可用后失败,但这并没有帮助。
设置spring.kafka.producer.retries: 0
或spring.kafka.producer.acks: 0
会导致(堆栈跟踪不完整):
Caused by: org.apache.kafka.common.config.ConfigException: Must set retries to non-zero when using the idempotent producer.
Caused by: org.apache.kafka.common.config.ConfigException: Must set acks to all in order to use the idempotent producer. Otherwise we cannot guarantee idempotence.
当Kafka服务器不可用并且启用了事务管理时,是否有一些设置组合会使Kafka Producer在超时后失败?那有可能吗?
答案 0 :(得分:2)
Spring-Kafka使用DefaultAfterRollbackProcessor
来查找失败的偏移量,然后重试-这将继续循环直到正确处理偏移量为止。这是默认行为。如果交易失败取决于您rollbackFor
的{{1}}属性,您将回滚。
您有一个特殊情况,如果Kafka服务器不可用,它将回滚。您可以通过实现@Transactional
来创建自己的处理器。由于连接超时,您将需要从回滚中识别出常规回滚。
编辑:
您还可以在AfterRollbackProcessor
上定义属性noRollbackFor
以排除@Transactional
并使此异常到达TimeoutException
。您可以创建自定义ExceptionHandler并在容器上使用Container
。您可以阅读有关容器错误处理程序here