Apache kafka 在数据库和Kafka producer之间同步事务

Apache kafka 在数据库和Kafka producer之间同步事务,apache-kafka,spring-transactions,spring-kafka,distributed-transactions,Apache Kafka,Spring Transactions,Spring Kafka,Distributed Transactions,我们有一个微服务体系结构,使用Kafka作为服务之间的通信机制。有些服务有自己的数据库。假设用户调用服务a,这将导致在该服务的数据库中创建一条记录(或一组记录)。此外,该事件应作为卡夫卡主题的一项报告给其他服务部门。只有成功更新Kafka主题(基本上围绕数据库更新和Kafka更新创建分布式事务)时,才能确保写入数据库记录的最佳方法是什么 我们正在考虑使用(在Spring Boot WebFlux服务中),我可以看到它有一个,但据我所知,这更多的是关于Kafka事务本身(确保Kafka生产者和消费

我们有一个微服务体系结构,使用Kafka作为服务之间的通信机制。有些服务有自己的数据库。假设用户调用服务a,这将导致在该服务的数据库中创建一条记录(或一组记录)。此外,该事件应作为卡夫卡主题的一项报告给其他服务部门。只有成功更新Kafka主题(基本上围绕数据库更新和Kafka更新创建分布式事务)时,才能确保写入数据库记录的最佳方法是什么

我们正在考虑使用(在Spring Boot WebFlux服务中),我可以看到它有一个,但据我所知,这更多的是关于Kafka事务本身(确保Kafka生产者和消费者之间的一致性),而不是跨两个系统同步事务(请参阅:“Kafka不支持XA,您必须处理DB tx可能在Kafka tx回滚时提交的可能性。”)。此外,我认为该类依赖于Spring的事务框架,至少据我目前所知,该框架是线程绑定的,如果使用反应式方法(例如WebFlux),则无法工作一个操作的不同部分可以在不同的线程上执行。(我们使用的是手动处理事务,而不是使用Spring的框架。)

我能想到的一些选择:

  • 不要将数据写入数据库:只将其写入Kafka。然后使用使用者(在服务a中)更新数据库。这似乎不是最有效的方法,并且会出现问题,因为用户调用的服务无法立即看到它刚刚创建的数据库更改
  • 不要直接写入Kafka:只写入数据库,并使用类似的方法向Kafka报告更改。这里的问题是更改基于单个数据库记录,而要存储在Kafka中的重要业务事件可能涉及来自多个表的数据组合
  • 首先写入数据库(如果失败,则不执行任何操作,只抛出异常)。然后,在写入Kafka时,假设写入可能失败。使用内置的自动重试功能使其继续尝试一段时间。如果最终完全失败,请尝试写入死信队列,并创建某种手动机制供管理员进行排序。如果写入DLQ失败(即卡夫卡完全停机),只需以其他方式将其记录(例如,记录到数据库),然后再次创建某种手动机制供管理员进行排序
  • 有人对上述内容有任何想法或建议,或者能够纠正我上述假设中的任何错误吗


    提前感谢!

    我建议使用稍微修改过的方法2

    仅写入数据库,但除了实际的表写入之外,还要写入“事件”在同一数据库中的一个特殊表中;这些事件记录将包含您需要的聚合。最简单的方法是,您只需插入另一个实体,例如JPA映射的实体,该实体包含一个JSON属性和聚合负载。当然,这可以通过事务侦听器/框架组件的某种方式实现自动化

    然后使用Debezium从该表捕获更改并将其流式传输到Kafka。这样,您就拥有了两者:Kafka中的最终一致状态(Kafka中的事件可能会落后,或者在重新启动后第二次看到一些事件,但最终它们将反映数据库状态)不需要分布式事务,也不需要您所追求的业务级事件语义

    (免责声明:我是Debezium的负责人;有趣的是,我正在写一篇博客文章,更详细地讨论这种方法)

    这些是帖子


    首先,我不得不说,我不是卡夫卡,也不是Spring专家,但我认为在编写独立资源时,这更像是一个概念上的挑战,解决方案应该适应您的技术堆栈。此外,我应该说,此解决方案试图在没有像Debezium这样的外部组件的情况下解决问题,因为在我看来,每一个额外的组件都会给测试、维护和运行一个应用程序带来挑战,而在选择这样一个选项时,这个挑战往往被低估。而且,并非每个数据库都可以用作Debezium源

    为了确保我们谈论的是相同的目标,让我们在一个简化的航空公司示例中澄清一下情况,客户可以购买机票。成功订购后,客户将收到一条消息(邮件、推送通知等),该消息由外部消息系统(我们必须与之交谈的系统)发送

    在传统的JMS世界中,我们的数据库(存储订单的地方)之间有一个XA事务JMS提供程序如下所示:客户端为我们的应用程序设置启动事务的顺序。应用程序将该顺序存储在其数据库中。然后将消息发送到JMS,您可以提交事务。两个操作都参与事务,即使它们与自己的资源进行通信。作为XA transac我们很好

    让我们将Kafka(或任何其他无法参与XA事务的资源)带到游戏中。由于不再存在同步两个事务的协调器,下面的主要思想是将处理分为两部分,并使用持久状态

    当您将订单存储在数据库中时,您还可以将消息(连同聚合数据)存储在您希望稍后发送给Kafka的同一数据库中(例如,作为CLOB列中的JSON)。相同的资源–ACID保证,到目前为止一切正常。现在您需要一种机制来轮询您的“Kafkatask”-表,以查找需要执行的新任务