【问题标题】:Microservices and duplicating database tables微服务和复制数据库表
【发布时间】:2018-10-22 23:19:40
【问题描述】:

我一直致力于将单体系统 (.NET) 拆分为更小的有界上下文,从而拆分为多个类库。地址记录是系统的核心,因此对于不相关的实体返回 MASTER 地址记录很重要。每个微服务都有自己的数据库,其中包含与该有界上下文相关的表。我遇到了关于地址记录或地址实体的挑战。这两个有界上下文或库都需要使用地址表和相关的查找表,例如州、国家/地区等。我是否应该在每个数据库中复制与地址相关的表并复制与地址相关的域类?如果我重复,我将在两个数据库中都有大量重复的地址记录,这让我陷入困境。如果我将地址表放在“位置服务”之类的地方,则很难在搜索结果中显示地址字段。也许这不是微服务的合适场景?

示例: Microservice-1(产品A) 事件 -> 一对一 -> 地址

微服务 2(产品 B) 消火栓 -> 一对一 -> 地址

Microservice-3(产品 C) 检查 -> 多对一 -> 地址

【问题讨论】:

    标签: microservices


    【解决方案1】:

    为了更好地说明,我假设每个微服务都有 REST API。

    在我看来,您有一个 IncidentService、一个 FireHydrantService 和一个 InspectionService,它们都依赖于 LocationService

    通过遵循微服务方法,您必须了解要实现的两个目标:

    • 松耦合
    • 内聚行为

    这意味着不允许您的服务共享数据库(它可以在物理上相同,但在逻辑上不一样),因此服务无法修改不同服务的数据或绕过负责的服务直接访问其数据.这必须由负责的服务通过其 API 专门完成。否则,内聚行为将面临风险。

    RESTful API 非常棒,因为我们还希望松散耦合。

    资源可能如下所示:

    "incident": {
        "time": "...",
        "location" : {
            "name": "an arbitrary address"
            "href": "apis.yourdomain.com/locationservice/address/1"
            "type": "application/json"
        },
        "nearestHydrant": {
            "name": "hydrant 42"
            "href": "apis.yourdomain.com/firehydrantservice/hydrant/42"
            "type": "application/json"
        }
    }
    

    如您所见,这些实体(更好地表示)仅表示为链接引用(其中的实体)负责的服务。这种耦合是松散的,因为在您的应用程序的整个生命周期中,链接作为实体的表示不太可能发生变化。通过命名字段,您还可以获得FireHydrantIncident 之间关系的语义。

    但是事情很容易变得复杂。假设像“域对象只能由负责的服务发出”这样的规则,以保持内聚行为。这意味着只允许FireHydrantServiceFireHydrant 服务。 现在想象一个像“Incident at address 1”这样的请求。应该向哪个服务查询最近的FireHydrant?按照上述规则,它应该是FireHydrantService。但是FireHydrantService 怎么知道,它不知道 nearest 是什么意思?

    在这种情况下,有一种叫做非权威缓存的东西(也可以保存在数据库中)。这只是意味着LocationService 允许将FireHydrant 存储在缓存或数据库中,但不允许与他人共享。这样,仍然遵循上述规则,并且内聚行为仍然存在。非权威缓存不需要反映完整的域对象FireHydrant,而是满足用例所需的一切。 所以IncidentServiceFireHydrantService 询问最近的FireHydrant(s),什么被委托给LocationService,它查询其非权威缓存以查找最近的位置,类型为FireHydrant,响应是一个参考(链接) 到FireHydrantService 本身,它检查FireHydrant 是否有它的Inspection,因此根据业务规则是否有效(如果不是,它将检查下一个)并返回一个参考(链接)到IncidentService

    我的经验法则是,每个服务都可以在每个域对象上进行查询,但只能服务于它负责的域对象。 “查询域对象”可以存在于上述非权威缓存中。这当然会导致重复,有趣的部分是让它们保持同步。立即想到的一件事是使用事件溯源。 Service 发出事件“Hydrant 42 out of order”,LocationService 将从其缓存中删除 Hydrant 42。

    【讨论】:

      【解决方案2】:

      由于我来自 java 背景,我不知道上面提到的与 .Net 相关的库和限界上下文。但我会尝试以一般的方式回答这个问题。 为了解决这个问题,您可以将地址相关的表存储在不同的数据库中,这三个微服务都可以访问这些表。

      由于每个微服务的查找表都将具有相同的表/数据,因此您可以对所有微服务使用相同的查找表。如果您的地址表有不同的列,那么您可以将每个微服务的地址存储在不同的表中,否则您可以通过存储每个微服务的 address_type 将数据存储在同一个表中。

      【讨论】:

        猜你喜欢
        • 2022-01-08
        • 2019-12-11
        • 1970-01-01
        • 2017-04-22
        • 1970-01-01
        • 2015-09-14
        • 2019-08-02
        • 2021-01-01
        • 2015-06-28
        相关资源
        最近更新 更多