微服务和复制数据库表

时间:2018-05-12 21:53:39

标签: microservices

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

实施例: 微服务-1(产品A) 事件 - >一对一 - >地址

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

微服务-3(产品C) 检查 - >多对一 - >地址

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

为了更好地说明,我假设每个微服务都使用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之间关系的语义。

但是事情很容易变得复杂。假设有一个规则,例如“域对象只能由负责的服务发出”,以维护内聚行为。这意味着仅FireHydrantService被允许服务FireHydrant。 现在想象一个请求,例如“ {1}在地址1”。应该为最近的Incident查询哪个服务?按照上述规则,它应该是FireHydrant。但是FireHydrantService怎么知道,不知道最近是什么意思?

在这种情况下,存在一种称为非权威性缓存(也可以持久存储在数据库中)的东西。这仅表示允许FireHydrantServiceLocationService存储在缓存或数据库中,但不允许与其他人共享。这样,仍然遵循上述规则,并且内聚行为仍在眼前。非权威性缓存不需要反映完整的域对象FireHydrant,而是需要满足UseCases的所有必要条件。 因此,FireHydrantIncidentService询问最近的FireHydrantService,什么被委托给FireHydrant(s),并向其非权威性缓存查询类型为{{1 }},该响应是对LocationService本身的引用(链接),它检查FireHydrant是否具有其FireHydrantService,因此根据业务规则是有效的(如果不是,则将检查下一个)并返回对FireHydrant的引用(链接)。

我的经验法则是,可以在每个域对象上查询每个服务,但是只能服务它负责的域对象。 “在域对象上查询”可以存在于前面提到的非权威性缓存中。这当然会导致重复,而有趣的部分是使它们保持同步。立即想到的是事件源的使用。服务发出事件“消防栓42乱序”,LocationService将从其缓存中删除消防栓42。