当 Pod 有多个副本时如何处理多个更新事件

问题描述

我有两个服务,分别是产品和订单。 OrderDb 中的订单表具有 price 和 productId 列,用于存储订购的产品价格和产品 ID。订单服务有 3 个副本。

现在,假设订购了一个产品,它的 id 为 80,并且从产品服务触发了一系列顺序更新事件以订购该特定产品的服务:

event1:{productId: 80,price: 500}
event2:{productId: 80,price: 600}
event3:{productId: 80,price: 400}
event4:{productId: 80,price: 900}
event5:{productId: 80,price: 100}

因此该产品的最终价格应为 100,但有时这些事件以随机顺序处理,例如

event1:{productId: 80,price: 600}
event5:{productId: 80,price: 100}
event4:{productId: 80,price: 900}
event3:{productId: 80,price: 400}

由于事件 3 最后处理,价格变为 400。

解决方法

这通常取决于您的数据库。我看到你把 NATS 放在标签中,所以我假设你的意思是你有某种工作队列模型,但你可能有一个记录数据库,它有自己的一致性模型。对于要防止出现乱序或多次交付的事件流系统,您可以在队列消息中包含更多信息,例如对象版本或之前的价格。在后一种情况下,更简单的情况是

event1:{productId: 80,price: 500,oldPrice: 0}
event2:{productId: 80,price: 600,oldPrice: 500}
event3:{productId: 80,price: 400,oldPrice: 600}
event4:{productId: 80,price: 900,oldPrice: 400}
event5:{productId: 80,price: 100,oldPrice: 900}

如果基本状态不再匹配,这将使您的代码拒绝应用该操作。但这非常有限,您不希望重新订购后一切都失败,您只需要收敛行为。这就是我大喊“矢量时钟”并跳出窗外的地方。设计分布式、融合系统确实相当困难,从术语 CRDT 开始。

,

我认为您的问题是由于不完全了解您的消息代理(可能是 NATS)的交付保证。

首先,您应该确定您需要哪些保证,然后选择一种消息传递技术。如果您需要对所有事件、关于一个实体的所有事件进行严格排序,或者根本不需要排序,这会产生巨大的差异。交付语义也是如此:至多一次、至少一次、恰好一次。

如果这些事情都清楚,那么选择满足这些要求的消息传递技术,否则你最终会通过变通方法增加复杂性(就像 coderanger 的建议)。有许多消息传递协议,例如 AMQP、MQTT、NATS、Kafka 等...

请注意,这是拥有分布式架构的成本!做微服务的时候没办法考虑分布式系统的问题。