Microservices 微服务和复制数据库表

Microservices 微服务和复制数据库表,microservices,Microservices,我一直致力于将单片系统(.NET)拆分为更小的有界上下文,从而拆分为多个类库。地址记录是系统的核心,因此不相关的实体返回主地址记录非常重要。每个微服务都有自己的数据库,其中包含与该有界上下文相关的表。我遇到了一个关于地址记录或地址实体的挑战。这两个有边界的上下文或库都需要使用地址表和相关的查找表,如State、Country等。我是否应该复制每个数据库中与地址相关的表,并复制与地址相关的域类?如果复制,两个数据库中都会有大量重复的地址记录,这让我陷入困境。如果我把地址表放在类似“定位服务”的地方

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

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

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

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

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


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

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

在我看来,您有一个
意外服务
、一个
消防栓服务
和一个
检查服务
,它们都依赖于
位置服务

通过遵循微服务方法,您必须意识到您想要实现的两个目标:

  • 松耦合
  • 内聚行为
这意味着不允许您的服务共享数据库(它在物理上可能相同,但在逻辑上可能不同),因此服务无法修改不同服务的数据或通过绕过负责的服务直接访问其数据。这必须由责任服务通过其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"
    }
}
如您所见,这些enitite(更好的表示)仅表示为负责服务中的链接引用(实体)。这种耦合是松散的,因为在应用程序的整个生命周期中,链接作为实体的表示形式不太可能更改。通过命名字段,您还可以获得
消防栓
事件
之间关系的语义

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

在这种情况下,有一种称为非权威缓存(也可以在数据库中持久化)的东西。这只是意味着允许
LocationService
消防栓
存储在缓存或数据库中,但不允许与其他人共享。这样,上述规则仍然被遵循,而内聚行为仍然在手边。非权威缓存不需要反映完整的域对象
firehrupt
,而是反映满足用例所需的一切。 因此,
IncidentService
FireHydrantService
询问最近的
FireHydrantService
,委托给
LocationService
的是什么,该服务使用
FireHydrant
类型查询其非权威缓存中最近的位置,响应是一个参考(链接)到
消防栓服务
本身,检查
消防栓
是否进行了
检查
,因此根据业务规则是否有效(如果没有,则检查下一次),并返回对
意外服务
的引用(链接)

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