微服务:如何处理外键关系


85

微服务架构建议每个服务应处理自己的数据。因此,任何依赖于其他服务(服务B)拥有的数据的服务(服务A)都不应通过直接DB调用而是通过第二个服务(服务B)提供的api访问此类数据。

因此,微服务最佳实践对检查外键约束有何建议?

示例:我正在开发产品的交付功能(微服务1),并且某些产品只能交付到产品表中提到的某些位置,只有产品微服务(微服务2)可以访问该表。

我如何确保微服务1(即送货功能)不会将订单送到未服务的地点。我有这个问题,因为交付功能无法直接访问产品数据库,因此在将交付订单放入交付数据库中时,在数据库级别没有适用的约束(无法检查产品数据库中是否存在外键匹配项)或表格)。

Answers:


71

可以将共享数据库用于多个微服务。您可以在以下链接中找到微服务数据管理的模式:http : //microservices.io/patterns/data/database-per-service.html。顺便说一下,对于微服务架构而言,这是一个非常有用的博客。

对于您的情况,您更喜欢按服务模式使用数据库。这使微服务更加自治。在这种情况下,您应该在多个微服务之间复制一些数据。您可以在微服务之间通过api调用共享数据,也可以通过异步消息共享数据。这取决于您的基础架构和数据更改的频率。如果不经常更改,则应使用异步事件复制数据。

在您的示例中,交付服务可以复制交付位置和产品信息。产品服务管理产品和位置。然后将所需数据与异步消息一起复制到Delivery Service的数据库中(例如,您可以使用Rabbit mq或apache kafka)。交付服务不会更改产品和位置数据,但会在完成工作时使用这些数据。如果交付服务使用的部分产品数据经常更改,那么使用异步消息传递进行数据复制将非常昂贵。在这种情况下,您应该在产品和交付服务之间进行api调用。送货服务要求产品服务检查产品是否可送货到特定地点。送货服务要求产品服务提供产品和位置的标识符(名称,ID等)。这些标识符可以从最终用户那里获取,也可以在微服务之间共享。由于此处的微服务数据库不同,因此我们无法在这些微服务的数据之间定义外键。

Api呼叫可能更易于实现,但此选项的网络成本较高。此外,在进行api调用时,您的服务也不太自治。因为在您的示例中,当产品服务关闭时,交付服务无法执行其工作。如果使用异步消息传递复制数据,则进行传递所需的数据位于传递微服务的数据库中。当产品服务不起作用时,您将可以交货。


2
好答案。我使用API​​调用,但是它还需要对来自另一个服务的数据进行排序和分页。您知道针对这种情况的最佳方法吗?
tranceholic

6
您应该将与分页和排序相关的参数添加到api。然后,api的使用者将负责按照正确的顺序获取正确的页面。有一些技术可用于定义GraphQL之类的api。据我所知,这些技术已经具有排序和分页功能。如果您不使用这种技术,则可以简单地从客户端获取参数,并使用它们返回按页面排序的数据。
AliSağlam'Dec 21'17

1
的确是个好答案!
TS

2
但是,您是否保留外键?例如:每篇博客文章都会有很多评论。Monolith将在博客表中添加带有外键的注释表。但是在微服务中,我们将提供两种服务。服务1:使用这些表字段(PostID,名称,内容)发布Microservie服务2:使用这些表字段(CommentID,PostID,Cpmment)注释Microservie问题是,我们在服务2(注释微服务)中是否需要“ PostID”?我想答案是肯定的,因为我们需要知道哪个评论属于哪个帖子。我的理解正确吗?
rakesh mehra

1
如何将系统划分为微服务是完全不同的故事,但是如果您决定创建2个微服务(如post和comment),则您需要在comment微服务上有post标识符,因为每个评论都属于一个帖子。但是,这并不意味着您需要在这些表之间定义FK。FK只是RDBMS世界中的一个约束,有助于确保数据完整性和一致性。如果将这些微服务的数据保存在单独的模式中,则无法定义FK,甚至可能将一个人的数据保存在不适用FK的nosql db(对于注释微服务而言很有意义)上。
AliSağlam20年

24

分发代码以减少耦合时,您要避免资源共享,而数据是您要避免共享的资源。

另一点是,系统中只有一个组件拥有数据(用于状态更改操作),其他组件可以读取但不能写入,它们可以具有数据的副本,或者您可以共享可用于获取最新状态的视图模型一个对象。

引入引用完整性将重新引入耦合,相反,您想对主键使用Guid之类的东西,它们将由对象的创建者创建,其余全部与管理最终一致性有关。

看看Udi Dahan在NDC奥斯陆演讲,了解更多详细信息

希望这可以帮助


2
乌迪·达汉(Udi Dahan)演讲的链接非常有趣
Comencau,

3

第一个解决方案:API组成

 Implement a query by defining an API Composer, which invoking the
 services that own the data and performs an in-memory join of the
 results

在此处输入图片说明

第二种解决方案:CQRS

Define a view database, which is a read-only replica that is designed to support that 
query. The application keeps the replica up to data by subscribing to Domain events 
published by the service that own the data.

在此处输入图片说明


1

2020年的更新是使用像Debezium这样的Change Data Capture工具。Debezium将监视您的数据库表中的更改,并将其流式传输到Kafka / Pulsar(其他管道),然后您的订户可以捕获更改并进行同步。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.