步骤 a.-(保存在 Order DB 中)和 b.-(发布消息)应该在事务中以原子方式执行。我怎样才能做到这一点?
Kafka 目前不支持事务(因此也不支持回滚或提交),您需要同步这样的事情。简而言之:你不能做你想做的事。当KIP-98合并时,这将在不久的将来发生变化,但这可能还需要一些时间。此外,即使使用 Kafka 中的事务,跨两个系统的原子事务也是一件非常困难的事情,接下来的一切只会通过 Kafka 中的事务支持得到改进,它仍然不能完全解决您的问题。为此,您需要考虑在您的系统中实施某种形式的两阶段提交。
您可以通过配置生产者属性获得一些接近,但最终您必须为您的一个系统(MariaDB 或 Kafka)选择至少一次或最多一次。
让我们从您在 Kafka 中可以做的事情开始,确保消息的传递,然后我们将深入探讨您对整个流程流程的选择以及后果是什么。
保证交货
您可以使用参数acks配置在将请求返回给您之前必须有多少个代理确认收到您的消息:通过将其设置为all您告诉代理等待直到所有副本都确认您的消息,然后再向您返回答案. 这仍然不能 100% 保证您的消息不会丢失,因为它只被写入页面缓存,并且理论上存在代理在将其持久化到磁盘之前失败的情况,其中消息可能仍然丢失。但这与您将获得的一样好保证。您可以通过降低经纪人强制 fsync 到磁盘的时间间隔来进一步降低数据丢失的风险(强调文本和/或flush.ms) 但请注意,这些值可能会带来严重的性能损失。
除了这些设置之外,您还需要等待您的 Kafka 生产者将您的请求的响应返回给您,并检查是否发生异常。这种关系与您问题的第二部分有关,因此我将进一步讨论。如果响应是干净的,您可以尽可能确定您的数据已到达 Kafka 并开始担心 MariaDB。
到目前为止,我们所介绍的所有内容都只涉及如何确保 Kafka 收到您的消息,但您还需要将数据写入 MariaDB,这也可能会失败,这将使得有必要召回您可能已经发送到 Kafka 的消息 -这是你不能做的。
所以基本上你需要选择一个系统,在这个系统中你能够更好地处理重复/缺失值(取决于你是否重新发送部分失败),这将影响你做事的顺序。
选项1

在此选项中,您在 MariaDB 中初始化事务,然后将消息发送到 Kafka,等待响应,如果发送成功,您在 MariaDB 中提交事务。如果发送到 Kafka 失败,您可以在 MariaDB 中回滚您的事务,一切都很好。但是,如果发送到 Kafka 是成功的,并且您对 MariaDB 的提交由于某种原因而失败,那么就无法从 Kafka 取回消息。因此,如果您稍后重新发送所有内容,您将要么在 MariaDB 中丢失一条消息,要么在 Kafka 中有一条重复的消息。
选项 2

这几乎正好相反,但您可能更好地删除用 MariaDB 编写的消息,具体取决于您的数据模型。
当然,您可以通过跟踪失败的发送并稍后重试这些方法来缓解这两种方法,但所有这些更多的是对更大问题的创可贴。
就我个人而言,我会采用方法 1,因为提交失败的机会应该比发送本身要小一些,并在 Kafka 的另一端实施某种欺骗检查。
这与上一个有关:我发送消息是: orderSource.output().send(MessageBuilder.withPayload(order).build()); 此操作是异步的,并且始终返回 true,无论 Kafka 代理是否关闭。我如何知道消息已到达 Kafka 代理?
首先,我承认我对 Spring 不熟悉,所以这可能对您没有用处,但以下代码片段说明了一种检查产生异常响应的方法。通过调用 flush 你阻塞直到所有发送完成(失败或成功),然后检查结果。
Producer<String, String> producer = new KafkaProducer<>(myConfig);
final ArrayList<Exception> exceptionList = new ArrayList<>();
for(MessageType message : messages){
producer.send(new ProducerRecord<String, String>("myTopic", message.getKey(), message.getValue()), new Callback() {
@Override
public void onCompletion(RecordMetadata metadata, Exception exception) {
if (exception != null) {
exceptionList.add(exception);
}
}
});
}
producer.flush();
if (!exceptionList.isEmpty()) {
// do stuff
}