微服务范式下的主数据管理策略

14

正在迁移一个庞大的单块应用程序到微服务范式,不用说域标识和映射到不同的微服务以及编排已经是一项相当艰巨的任务了。 现在,由于以前的应用程序将主数据存储在同一个模式中,对于我来说,在新范式中管理它变得很困难,我的选择有:

  1. 在每个微服务中复制相同的主数据:优点:在应用程序缓存中时,可以快速工作且无需查找,应用程序本身就像一个真正的真实来源。缺点:特定服务上的主数据更新可能会导致在使用此数据进行通信时出现不一致性,对主数据的更新可能会导致严重的一致性问题。
  2. 将主数据作为独立的微服务托管:优点:主数据的单一来源。缺点:性能会受到影响,因为每次查找时都需要通过服务调用。
  3. 创建分布式缓存并将其公开给多个微服务:将打破微服务数据的“单一真实来源”原则,但可以确保性能和一致性,因为它是一个写入时即通过实现。

对以上任何想法或任何实现策略的想法都会非常有帮助...

Vaibhav


2
你正在构建一个分布式单体应用。你的三种方法中任何一种都会导致失败,因为微服务之间通过共享数据相互绑定。只有当你成功将应用程序切分成独立的部分时,才能真正获得微服务的好处。 - Ulrich Eckhardt
3个回答

19
针对这个问题或困境的解决方案取决于您当前架构的一些信息。
- 您的微服务之间如何通信? 您是否使用命令/查询作为直接调用和通过某个队列的事件进行通信?
- 您的主数据有多大? 它是某种配置或少量缓存数据,作为某些常量或设置使用吗?
如果您的其中一种通信机制是通过来自某个队列的事件异步完成,并且您不处理非常频繁更改的大量数据,则我的建议是:
1. 创建专用主数据微服务。 该微服务将是您的主数据所有者。它将是唯一允许直接更改其中实体的服务。
2. 在更改主数据微服务中的每个实体时,在队列上发布事件。 每当有人在主数据微服务中创建、更新或删除实体时,您都将在某个队列上发布有关这些更改的事件。
3. 订阅主数据微服务事件。所有需要使用主数据微服务数据的其他微服务都会订阅其使用的实体的事件,并将它们本地保存在其数据库中。该数据或主数据子集将被保存为本地使用的副本。只有在主数据微服务发布实体已更改的事件时,这些主数据实体才能通过这些事件进行更改。任何其他类型的更改都将被禁止,因为这将在本地数据副本和其在主数据微服务中的真实源之间创建差异。

优点:

通过此方法,您只需拥有一个主数据信息的真实来源。所有其他微服务仅使用来自主数据微服务的所需数据或数据子集。他们可以忽略其他数据。另一个优点是,您的微服务可以独立运行,而不必直接调用主数据微服务以获取所需数据。

缺点:

缺点是您需要在多个微服务中复制数据。另一个问题是您需要处理分布式系统的复杂性,但您已经在做到这一点了;)

关于您提供的选择的一些评论:

 

在每个微服务中复制相同的主数据:优点:在应用程序缓存中工作时快速且无需查找,应用程序在内部进行访问。

 

缺点:需要在多个服务之间维护数据一致性,并且可能存在更新冲突。

建议:

与其在每个微服务中复制主数据,不如使用事件驱动的方法实现主数据微服务。这将确保数据的唯一来源并减少数据冗余。虽然这可能会增加系统的复杂性,但它可以避免数据一致性和更新冲突等问题。

将主数据作为真正的"source of truth"。缺点是:特定服务中主数据的任何更新都可能导致不一致性,因为在使用该数据进行通信时,对主数据的更新可能会在各个服务之间引起严重的一致性问题。
我的建议部分地涵盖了以上方法,只是没有直接调用。假设您将使用队列。即使您不使用队列,您也可以通过某些通知系统通知使用主数据微服务的微服务,然后仅在这种情况下让它们调用您的主数据微服务以获取最新数据。而不是在每个需要主数据的微服务内部进行调用。那样效率非常低下。
将主数据作为单独的微服务托管:优点是:单一的主数据源。缺点是:性能有所下降,因为每当查找发生时,它总是通过网络进行服务调用。
我从上面的建议中提出的方案是将这个点与您关于在每个微服务中复制数据的第一个点相结合。
创建分布式缓存并将其公开给多个微服务:这将打破数据的"Single Source o Truth"原则,但可以确保性能和一致性,因为它是一个写入实现。

我不建议这样做。有很多理由不能这样做,其中一些你已经提到了。在执行此操作时需要考虑的一件事是,您将为多个微服务拥有一个连接的单一故障点。这违反了微服务的主要原则之一。


分布式系统的复杂性确实很高,我相信这是系统对数据拥有更多控制权的唯一出路。最终一致性是需要关注的问题,但在我的情况下,由于更新非常不频繁甚至不存在,这种方法是可行的! - vaibhav
1
太好了,希望有所帮助 :) - xargs

1
我们采用了以下一种方法:
1. 创建逻辑分组的主数据实体,这样就不会创建一个超级大的单体微服务。 2. 通过微服务提供逻辑分组主实体的管理(创建/更新/删除/读取)。因此,我们有5到6个微服务来管理不同逻辑组的主数据实体。 3. 每当任何功能模块请求主数据实体时,它首先在Redis缓存中查找,如果找不到,则调用对应于参考数据逻辑组的获取API微服务。 4. 微服务的获取API具有将主数据实体放入Redis缓存的实现。这样,任何对同一实体的后续请求都将在Redis缓存中为其他功能模块提供。 5. 当请求来自获取API或值对象正在更新时,Redis缓存会得到更新。
优点:
1. 所有值对象都可以从Redis缓存中集中访问。 2. Redis缓存提供更快的读取,而不是每次经过主数据实体的获取API。
缺点:
  1. 识别个体主数据实体的关键需要与其他功能模块进行沟通。

1
没有一种通用的方法来管理所有种类的主数据实体。以下是我在以前的项目中设定和遵循的内容:
1. 基于其行为/使用模式将主数据分离,而不是基于实体本身的设计。例如,用户使用“随时输入”功能搜索主数据,如城市名称或邮政编码。使用文本搜索工具如Redis/Elastic。两者都是持久性存储。
2. 不要将功能与主数据混合在一起。例如,假设我们创建了城市主数据,则不要将其与业务功能(如此城市是否可服务)结合在一起。
3. 提示:许多时候,多个主数据类型可以存储在两个实体中(如果我们使用RDBMS,则这很有用)以存储记录。例如,假设我们有城市、州和邮政编码主数据。创建两个表,主数据类型/类别和主数据本身。因此,我们只需要一个查询即可获取每种类型的记录。
以上方法的优点:
1. 通过限制访问它们所需的服务数量,基于行为的主数据访问模式的一致性。 2. 将不同的主数据实体转换为主数据的一致模板,从而减少了为不同的主数据定义多个实体的需要。参考#3。 3. 减少每次添加新实体时修改代码的工作量。 4. 支持1级层次结构。根据选择的州筛选城市。
缺点:
1. 仅支持1级层次结构。如果需要更复杂的过滤技术,则建议基于行为使用单独的模型。(参考#1)
我不认为使用#1和#3有任何好处。我也不认为会对性能造成影响,因为大多数情况下,这些调用可以与其他服务调用并行进行。使用编排而不是管弦乐。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接