跨微服务的数据一致性

San*_*Dey 26 design-patterns data-consistency akka microservices

虽然每个微服务通常都有自己的数据 - 但某些实体需要在多个服务之间保持一致.

对于高度分布式环境(如微服务架构)中的此类数据一致性要求,设计有哪些选择?当然,我不想要共享数据库体系结构,其中单个数据库管理所有服务的状态.这违反了孤立和无共享的原则.

我明白,微服务可以在创建,更新或删除实体时发布事件.对此事件感兴趣的所有其他微服务可以相应地更新其各自数据库中的链接实体.

这是可行的,但它会导致整个服务中的许多仔细和协调的编程工作.

Akka或任何其他框架可以解决这个用例吗?怎么样?

编辑1:
为清楚起见,添加下图.
基本上,我试图理解,如果今天有可用的框架可以解决这个数据一致性问题.

对于队列,我可以使用任何AMQP软件,如RabbitMQ或Qpid等.对于数据一致性框架,我不确定目前Akka或任何其他软件是否可以提供帮助.或者这种情况是如此罕见,以及这种反模式,不需要任何框架?
在此输入图像描述

Osw*_*ann 10

Microservices建筑风格试图让企业有小团队独立开发并在运行时自己的服务.看这.最难的部分是以有用的方式定义服务边界.当您发现分割应用程序的方式导致需求经常影响多个服务时,会告诉您重新考虑服务边界.当您感到强烈需要在服务之间共享实体时,情况也是如此.

所以一般的建议是尽量避免这种情况.但是,有些情况下你无法避免这种情况.由于良好的架构往往是在做出正确的权衡,这里有一些想法.

  1. 考虑使用服务接口(API)而不是直接数据库依赖关系表达依赖关系.这将允许每个服务团队根据需要更改其内部数据模式,并且只关注依赖性时的接口设计.这很有用,因为更容易添加其他API并慢慢弃用旧API而不是更改数据库设计以及所有相关的微服务(可能同时).换句话说,只要仍然支持旧的API,您仍然可以独立部署新的Microsoft服务版本.这是亚马逊CTO推荐的方法,他开创了许多微服务方法.以下是2006年与他的访谈推荐阅读.

  2. 每当你真的无法避免使用相同的数据库并且你以多个团队/服务需要相同实体的方式分割你的服务边界时,你会在微服务团队和负责数据方案的团队之间引入两个依赖关系:a )数据格式,b)实际数据.这不是不可能解决的,而只是在组织中有一些开销.如果您引入太多此类依赖项,您的组织可能会在开发过程中陷入瘫痪和放缓.

a)对数据方案的依赖性.无需更改微服务即可修改实体数据格式.要解耦这一点,您必须严格对实体数据方案进行版本控制,并在数据库中支持微服务当前使用的所有数据版本.这将允许微服务团队自行决定何时更新其服务以支持新版本的数据方案.这对所有用例都不可行,但它适用于许多用例.

b)对实际收集数据的依赖性.已经收集并且是微服务的已知版本的数据可以使用,但是当您有一些服务生成更新版本的数据而另一个服务依赖于它时会出现问题 - 但尚未升级为能够阅读最新版本.这个问题很难解决,并且在许多情况下表明您没有正确选择服务边界.通常,您别无选择,只能在升级数据库中的数据的同时推出依赖于数据的所有服务.一种更古怪的方法是同时编写不同版本的数据(主要在数据不可变时起作用).

要在一些其他情况下解决a)和b),可以通过hidden data duplication和减少依赖性eventual consistency.这意味着每个服务都存储自己的数据版本,并且只有在该服务的需求发生变化时才会修改它.这些服务可以通过监听公共数据流来实现.在这种情况下,您将使用基于事件的体系结构,在该体系结构中,您可以定义一组公共事件,这些事件可以由来自不同服务的侦听器排队并使用,这些服务将处理事件并存储与其相关的任何数据(可能会造成数据重复).现在,一些其他事件可能表明内部存储的数据必须更新,并且每个服务都有责任使用自己的数据副本.维持这种公共事件队列的技术是Kafka.


Ram*_*gil 5

理论局限性

要记住的一个重要警告是CAP定理

在存在分区的情况下,然后剩下两个选项:一致性或可用性。当选择一致性而非可用性时,如果由于网络分区而不能保证特定信息是最新的,则系统将返回错误或超时。

因此,通过“要求”某些实体在多个服务中保持一致,可以增加必须处理超时问题的可能性。

Akka分布式数据

Akka具有分布式数据模块,可在集群内共享信息:

通过直接复制和基于八卦的分发,所有数据条目都将散布到群集中的所有节点或具有特定角色的节点。您可以很好地控制读写一致性级别。


Bla*_*l42 5

这里同样的问题。我们在不同的微服务中拥有数据,并且在某些情况下,一个服务需要知道另一个微服务中是否存在特定实体。我们不希望服务相互调用来完成请求,因为这会增加响应时间并增加停机时间。它还增加了耦合深度的噩梦。客户端也不应该决定业务逻辑和数据验证/一致性。我们也不希望像“Saga Controllers”这样的中央服务提供服务之间的一致性。

因此,我们使用 Kafka 消息总线来通知观察服务“上游”服务的状态变化。即使在错误情况下,我们也非常努力地不要错过或忽略任何消息,并且我们使用 Martin Fowler 的“宽容读者”模式来尽可能松散地耦合。有时,服务会发生变化,变化后,它们可能需要来自其他服务的信息,这些信息之前可能已经在总线上发出,但现在已经消失了(即使 Kafka 也无法永远存储)。

我们现在决定将每个服务分为一个纯粹的、解耦的 Web 服务(RESTful),它执行实际工作,以及一个单独的连接器服务,它监听总线,也可以调用其他服务。该连接器在后台运行。它仅由总线消息触发。然后,它将尝试通过 REST 调用将数据添加到主服务。如果服务响应一致性错误,连接器将尝试通过从上游服务获取所需数据并根据需要注入来修复此问题。(我们无法负担批处理作业来“同步”数据块,因此我们只获取我们需要的数据)。如果有更好的想法,我们总是持开放态度,但“拉动”或“只是改变数据模型”并不是我们认为可行的......