将Kafka与JPA一起使用时的良好做法

时间:2018-06-26 22:57:59

标签: java spring-boot jpa apache-kafka

我目前正在使用JPA和Kafka的项目中。我正在尝试找到一套将这些操作结合起来的良好实践。

在现有代码中,生产者和jpa都在同一笔交易中使用,但是,据我所读,似乎他们并不共享交易。

@PostMapping
@Transactional
public XDto createX(@RequestBody XRequest request) {
    Xdto dto = xService.create(request);
    kafkaProducer.putToQueue(dto, Type.CREATE);
    return dto;
}

其中的kafka生产者定义如下:

public class KafkaProducer {
    @Autowired
    private KafkaTemplate<String, Type> template;

    public void putToQueue(Dto dto, Type eventType) {
        template.send("event", new Event(dto, eventType));
    }
}

这是结合jpa和kafka的有效用例,事务边界是否正确定义?

4 个答案:

答案 0 :(得分:7)

这在事务失败时将无法正常工作。卡夫卡互动不属于交易的一部分。

您可能想看看TransactionalEventListener,您可能想在AFTER_COMMIT事件中将消息写到kafka。即使这样,kafka发布也可能会失败。

另一个选择是在执行操作时使用jpa写入db。让debezium从您的数据库中读取更新的数据,并将其推送到kafka。该事件将采用不同的格式,但内容将更加丰富。

答案 1 :(得分:4)

通过查看您的问题,我假设您正在尝试实现OLTP系统的CDC(更改数据捕获),即将要进行事务处理的每个更改都记录到事务数据库中。有两种方法可以解决此问题。

  1. 应用程序代码对事务数据库和Kafka进行双重写入。它不一致并影响性能。这是不一致的,因为当您对两个独立的系统进行双重写入时,如果其中一个写入失败,则数据会被破坏,并且在事务流中将数据推送到Kafka会增加延迟,而您不想对此加以妥协。
  2. 从数据库提交中提取更改(数据库/应用程序级触发器或事务日志),并将其发送到Kafka。这是非常一致的,完全不会影响您的交易。一致,因为数据库提交日志是成功提交之后数据库事务的反映。有许多利用这种方法的解决方案,例如databusmaxwelldebezium等。

如果CDC是您的用例,请尝试使用任何可用的解决方案。

答案 2 :(得分:2)

正如其他人所说,您可以使用更改数据捕获来将应用于数据库的更改安全地传播到Apache Kafka。您无法在单个事务中更新数据库和Kafka,因为后者不支持任何类型的两阶段提交协议。

您可以CDC表本身,或者,如果您希望对发送给Kafka的结构有更多控制,请应用“发件箱”模式。在这种情况下,您的应用程序将写入其实际业务表以及包含要发送到Kafka的消息的“发件箱”表。您可以在此blog post中找到有关此方法的详细说明。

免责声明:我是这篇文章的作者,也是Debezium的负责人,Debezium是其他一些答案中提到的CDC解决方案之一。

答案 3 :(得分:0)

您不应将正在发送的消息发送给kafka。如果在无法将事件发送到kafka时需要逻辑,然后还原事务,则在这种情况下最好使用spring-retry。只需将与发送事件相关的代码放入带有注释的方法@Retryable中,并添加具有注释的@Recover方法,并将逻辑恢复到以前所做的更改的逻辑即可。