Spring Kafka / Spring Cloud Stream如何保证涉及数据库和Kafka的事务性/原子性?

时间:2019-04-26 13:18:59

标签: apache-kafka spring-cloud spring-cloud-stream spring-kafka

Spring Kafka(进而是Spring Cloud Stream)允许我们创建事务性生产者和处理者。我们可以在以下示例项目之一中看到该功能的实际作用:https://github.com/spring-cloud/spring-cloud-stream-samples/tree/master/transaction-kafka-samples

@Transactional
    @StreamListener(Processor.INPUT)
    @SendTo(Processor.OUTPUT)
    public PersonEvent process(PersonEvent data) {
        logger.info("Received event={}", data);
        Person person = new Person();
        person.setName(data.getName());

        if(shouldFail.get()) {
            shouldFail.set(false);
            throw new RuntimeException("Simulated network error");
        } else {
            //We fail every other request as a test
            shouldFail.set(true);
        }
        logger.info("Saving person={}", person);

        Person savedPerson = repository.save(person);

        PersonEvent event = new PersonEvent();
        event.setName(savedPerson.getName());
        event.setType("PersonSaved");
        logger.info("Sent event={}", event);
        return event;
    }

在此摘录中,有个Kafka主题的读物,一个数据库中的写操作和另一个Kafka主题的另一个写信,所有这些都是事务性的。

我想知道并想回答的是,从技术上如何实现和实施。

由于数据源和Kafka不参与XA事务(两阶段提交),因此该实现方式如何保证本地事务可以从Kafka读取,提交到数据库并以事务方式将所有这些内容写入Kafka? / p>

1 个答案:

答案 0 :(得分:1)

没有保证,仅在Kafka本身内。

Spring提供了事务同步,因此提交紧密并存,但DB可以提交而Kafka可以不提交。因此,您必须应对重复的可能性。

直接使用spring-kafka时,正确的方法不是与@Transactional一起使用,而是在侦听器容器中使用ChainedKafkaTransactionManager

请参见Transaction Synchronization

另请参阅Distributed transactions in Spring, with and without XA和“尽力而为1PC模式”作为背景。

但是,对于Stream,不支持链式事务管理器,因此,@Transactional是必需的(对于DB事务管理器)。这将提供与链式tx管理器类似的结果,首先在Kafka之前提交数据库。