为了更好地说明,我假设每个微服务都有 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"
}
}
如您所见,这些实体(更好地表示)仅表示为链接引用(其中的实体)负责的服务。这种耦合是松散的,因为在您的应用程序的整个生命周期中,链接作为实体的表示不太可能发生变化。通过命名字段,您还可以获得FireHydrant 和Incident 之间关系的语义。
但是事情很容易变得复杂。假设像“域对象只能由负责的服务发出”这样的规则,以保持内聚行为。这意味着只允许FireHydrantService 为FireHydrant 服务。
现在想象一个像“Incident at address 1”这样的请求。应该向哪个服务查询最近的FireHydrant?按照上述规则,它应该是FireHydrantService。但是FireHydrantService 怎么知道,它不知道 nearest 是什么意思?
在这种情况下,有一种叫做非权威缓存的东西(也可以保存在数据库中)。这只是意味着LocationService 允许将FireHydrant 存储在缓存或数据库中,但不允许与他人共享。这样,仍然遵循上述规则,并且内聚行为仍然存在。非权威缓存不需要反映完整的域对象FireHydrant,而是满足用例所需的一切。
所以IncidentService 向FireHydrantService 询问最近的FireHydrant(s),什么被委托给LocationService,它查询其非权威缓存以查找最近的位置,类型为FireHydrant,响应是一个参考(链接) 到FireHydrantService 本身,它检查FireHydrant 是否有它的Inspection,因此根据业务规则是否有效(如果不是,它将检查下一个)并返回一个参考(链接)到IncidentService。
我的经验法则是,每个服务都可以在每个域对象上进行查询,但只能服务于它负责的域对象。 “查询域对象”可以存在于上述非权威缓存中。这当然会导致重复,有趣的部分是让它们保持同步。立即想到的一件事是使用事件溯源。 Service 发出事件“Hydrant 42 out of order”,LocationService 将从其缓存中删除 Hydrant 42。