推理、部署与算力8979 字

为什么微服务架构需要聚合

·全库 371 / 611

《为什么微服务架构需要聚合》共 0.9 万字,通篇围绕 数据库、缓存、微服务、架构 展开,归在「推理、部署与算力」这一层。

覆盖数据库缓存微服务架构检索上下文

适合要把模型跑起来,还得跑得起的人

目录骨架(2 节)
  1. 如何定义聚合
  2. 为什么聚合

前言:

微服务可以将我们的东西组织成一个考虑周到且定义明确的单元。

一体式架构通常意味着组织中的每个工程师都会涉及到应用的每一部分,且业务体与其他实体紧密耦合,微服务让我们朝着不同的方向迈进。工程师团队应该专注于自身的业务领域,业务实体应该只和同领域的实体相耦合。

对领域的描述总是说起来容易,做起来难。例如有界上下文就是一个最近流行的模式,可以帮助我们组织工程师团队,并在更高层面对业务领域进行划分。

类似地,聚合模式可以帮助我们在更低的层面聚合数据。最初将这种模式定义为按照事务对相关实体进行分组的方式。

此外,它还为我们提供了分解一体式数据架构的蓝图,本质上是将高内聚的实体划分为单一的、原子性的组。

当然好处还远不止此。有趣的是,聚合模式似乎不像其他分布式软件设计模式那样广为人知,被广泛讨论或普遍实现。但它是构建微服务的基本单元。

预先进行聚合设计可以帮助我们避免各种问题,如例如实体之间的偶然依赖关系或引用泄漏,这些问题通常会妨碍对系统的扩展。下面看下什么是聚合。

聚合

聚合是Eric Evans在他的书中Domain-Driven Design提出的一种设计模式,尽管书中没有明确地讨论微服务体系结构或分布式系统,但已经对这些话题进行了阐述。

一个聚合定义为一个自包含的实体组,作为一个独立的原子的单元。对任意实体的修改都可能会影响到整个聚合。每个聚合的构成如下:

  • 边界。这是实体之间的界限,界定了哪些实体属于聚合,哪些不属于。
  • 实体。组中包含的业务对象实体。
  • 根。每个聚合会向外部暴露一个实体。聚合外部的对象仅可以引用聚合根,不能直接访问其他聚合内部的实体。

示意图如下:

上图中最外层的椭圆表示聚合的边界,里面是聚合根(紫色圆形)以及其他实体(绿色圆形)。

由于外部只能通过根来访问聚合,因此在聚合内部,只有根才能引用其他实体(非根实体之间不能相互引用)。

聚合根

换句话说,根服务是聚合与外界交互的代表,因此应该选择最合适的实体作为根。幸运的是,实体的选择通常比较简单。很多聚合都拥有一个清晰的、主要的实体,该实体上附加了很多其他实体。

下面展示一个简化的例子:用户聚合。

注意我们的聚合及其根的名称都叫"User"。User实体可能包含的属性,如名和姓,性别,出生日期,可能还会包括国民身份以及其他少量标量字段。

User和它关联的信息(Email (address), Phone (number), 和(mailing) Address)是一对多的关系。除了上面描述的内容外,在外面的聚合中可能还会包含其他用于代表用户偏好的实体。

很显然,User实体作为了聚合的根。除了名称相同外,User实体包含了有关用户的核心信息。此外,它还是聚合中产生其他实体的实体。即,如果移除了Phone,则聚合本身会被保留下来。这种场景下,脱离了User上下文的Phone是毫无意义的。但如果移除了User实体,那么聚合中的其他实体就会变得没有意义,成为微服务架构中没有目的性的孤儿实体。

User实体是可以从外部直接访问聚合的唯一实体。以ReST为例,意味着我们可以提供如下路径:

/users/{user-identifier}

但不能提供如下路径(不能直接访问电话实体):

/users/phones/{phone-identifier}

其他聚合可以保存到User的引用,如Order聚合可能会保存每个发起Order的User,每个User必须分配一个全局唯一标识符。

值对象

相比之下,其他实体仅需要本地标识符,聚合可以通过标识符消除其自身的歧义。如可以使用1,2,3来标识User的Phone。

这是因为Phone对外并无意义,其他任何聚合都不会单纯地请求Phone 2,仅会检索用户b4664e12–2b5b-47c8-b349–41e81848758f使用的Phone 2。

但即使这样,也应该限制发生的范围,其他聚合不能永久保存到用户手机的引用。

回到ReST的例子,我们认为对一个手机的可以接受的引用如下(通过用户来访问其手机):

资料里没有你的场景?

把你手上的数据和想解决的那个环节发上来,我们按具体情况回,不复述方法论。

发布需求