我有以下典型情况:
付款服务。
Orders DB Products DB
| |
--------------- ---------------- ----------------
| OrderService | | ProductService | | PaymentService |
--------------- ---------------- ----------------
| | |
| -------------------- |
--------------- | Kafka orders topic |-------------
---------------------
正常流程将是:
我无法处理错误案例,例如:让我们假设:
在这种情况下,想象一下,无论出于何种原因,订单服务都会发布UNDO_PRODUCT_RESERVATION消息,但不会收到PRODUCT_UNRESERVATION_COMPLETED消息,因此它会重试发布另一个UNDO_PRODUCT_RESERVATION消息。
现在,假设同一订单的两个UNDO_PRODUCT_RESERVATION消息最终到达ProductService。如果我处理它们,我最终可能会为产品设置无效库存。
在这种情况下,我如何实现幂等性?
更新
按照Artem的说明我现在可以检测到重复的消息(通过检查消息头)并忽略它们但是仍然可能存在以下情况,我不应该忽略重复的消息:
你能帮我提出一种支持这种情况的方法吗?我怎么能区分何时应该丢弃该消息或重新处理它?</ p>
答案 0 :(得分:2)
我们使用spring-integration-kafka在我们的微服务中使用Kafka生成和使用消息。在我们的例子中,我们将org.springframework.messaging.Message对象发送到主题,并在从字节数组反序列化后从主题中获取相同的类型。在Message实体中,除了消息有效负载之外还有消息ID,发送时间等标头值,这是您要从一个微服务转移到其他服务器的实际对象。我们使用唯一的message-id值来实现幂等性。在生产者方面,您必须实现一些逻辑以确保Message的message-id在多次生成时是相同的。这实际上与您的产品逻辑有关。在我们的例子中,我们使用发布事件使用本地事务,这在Chris Richardson的博客https://www.nginx.com/blog/event-driven-data-management-microservices/中有很好的描述。使用这种方法,我们可以在生产者端使用相同的message-id重新调用Message对象。在消费者方面,我们将所有消耗的消息id值保存到数据库,并在处理收到的消息之前检查此ID。如果我们看到一条消息的id在我们的持久存储中,我们就会忽略它。
在您的情况下,要实现幂等性:
关于UPDATE中描述的第二个场景,
我认为你应该改变主意。如果要实现更适合微服务架构的发布 - 订阅机制,则不应该在生产者端等待响应。在这种情况下,您等待其他消息以了解消费者是否消费该消息,如果消费者没有使用该消息,则再次发送消息。
下面的实施情况如何; 在生产者方面,您在生产者的交易中向Kafka发送消息。您应该提供一种机制来向kafka发送消息,只提交生产者端的事务。这是Atomicity问题,我给出了一个链接,上面显示了如何解决这个问题。
在消费者方面,您按顺序逐个轮询来自kafka主题的消息,并且只有在可以使用当前消息时才能获得下一条消息。如果没有消费,你就不应该得到下一条消息。因为下一条消息可能与当前消息有关,并且如果您使用下一条消息,则可能会损坏数据的一致性。消息没有消耗时,它不是生产者关心的问题。在消费者方面,您应该提供重试和重放机制来使用消息。
我认为你不应该等待生产者方面的回应。 Kafka是一个非常智能的工具,凭借其偏移提交功能,作为消费者,当您从主题轮询消息时,您不必使用消息。如果您在处理消息时遇到问题,则只需提交偏移量即可获取下一条消息。
通过上述实施,您不会遇到像&#34; 这样的问题我如何区分何时应丢弃该消息或重新处理该消息?&#34;
...问候
答案 1 :(得分:-1)
实际上,由于您提到的关于通过Apache Kafka组织多个微服务交易的复杂性,我开发了另一个概念并写了一篇关于它的博客。
如果您达到复杂状态,Kafka解决方案可能不再可行,您可能会发现它是一个有趣的读物。这里解释的时间太长了,但基本上它完全采用了Micro服务原则的J2EE容器,并且在Spring Boot + Netflix的帮助下,Micro Services之间提供了完整的事务支持。
Micro Services Fanout and Transaction Problems and Solutions with Spring Boot and Netflix