微服务数据复制模式

Microservice data replication patterns

在微服务架构中,我们通常有两种方式让2个微服务进行通信。假设服务 A 需要从服务 B 获取信息。第一个选项是远程调用,通常通过 HTTPS 同步,因此服务 A 查询由服务 B 托管的 API。

第二种方案是采用事件驱动架构,服务B的状态可以异步的发布和服务A的消费。使用此模型,服务 A 可以使用来自服务 B 的事件的信息更新自己的数据库,并且所有查询都在该数据库中本地进行。这种方法的优点是可以更好地解耦微服务,从开发到运营。但它有一些与数据复制相关的缺点。

第一个是磁盘的高消耗space,因为相同的数据可以驻留在需要它的微服务的数据库中。但在我看来,第二个是最糟糕的:如果服务 B 不能按需要快速处理其订阅,数据可能会变得陈旧,或者它不能在服务 B 创建的同时对服务 A 可用,因为模型的最终一致性。

假设我们使用 Kafka 作为事件中心,其主题配置为使用 7 天的数据保留。服务 A 在服务 B 发布其状态时保持同步。两周后,部署了一个新的服务 C,它的数据库需要用服务 B 持有的所有信息来充实。由于最旧的事件已经消失,我们只能从 Kafka 主题中获取部分信息。我的问题是 我们可以使用哪些模式来实现此微服务的数据库丰富(除了要求服务 B 将其所有当前状态重新发布到事件中心)。

你的担心是对的,但同时微服务的方法是让步。您以每项服务的单独数据库为代价获得松散耦合。微服务架构没有正确答案,实际上取决于您要实现的目标。

根据 CAP 定理,您必须在一致性和可用性之间进行折衷,在大多数情况下,我们会选择最终一致性。如果您的服务 A 与 B 不一致,那么它最终会一致,这就是以可用性为代价的权衡。

关于微服务的另一件事是,您只保留来自其他服务的数据引用,来自其他服务的实际数据可能非常有限,但绝对不会太多。而且只有当复制数据使您的服务独立和自主时,这也是如此,如果即使在复制数据后您也无法实现任何目标,那么就没有意义。例如您的运输服务将具有完整的订单转换历史记录,但您的预订服务仅具有最新的订单状态(例如,在运输中、在船上等)。用户去预订,你显示订单的当前状态。但是,如果用户单击详细信息,您会从运输微服务中获取所有订单转换历史记录。现在,在某个时候您的运输服务出现故障,您的用户会来检查您的状态,您至少拥有当前订单状态,即使您无法显示详细信息,因为订单状态已在预订服务中复制。

关于后期加入系统的新服务,事件溯源是您用于此类场景的模式。它的模式很复杂,但它将把你新添加的服务带到你想要的状态。您基本上将所有事件保存在事件存储中并重放它们以获得系统的当前状态,并使用这些事件预填充服务 C 数据库。

有2个选项:

  1. 您可以为单个主题启用 Kafka 日志压缩。这将保留给定键的最新值并丢弃旧更新。这节省了 space,并且在给定的保留期限内比正常模式保存了更多的数据

  2. 假设你每天备份服务B的数据库,在引入新的服务C时,你需要先从B的最新备份创建C的初始状态,然后从表示备份后数据的特定偏移量 ID 重放 Kafka 主题事件。