DOMA

Uber 复杂微服务联系图

Domain-Oriented Microservice Architecture

如果我们可以将微服务视为 I/O 绑定库,而将“微服务架构”视为大型的分布式应用程序,则可以使用众所周知的架构来思考如何组织代码。因此,“面向域的微服务体系结构”大量借鉴了组织代码的既定方法,例如域驱动设计,干净体系结构,面向服务的体系结构以及面向对象和面向接口的设计模式。我们认为 DOMA 仅是创新,因为它是在大型组织的大型分布式系统中利用既定设计原则的相对新颖的方法。

与 DOMA 相关的核心原理和术语如下:

  • 我们不是围绕单个微服务,而是围绕相关微服务的集合。我们称这些域。

  • 我们进一步创建我们称为层的域的集合。域所属的层确定了允许该域内的微服务承担什么依赖性。我们称这种层设计。

  • 我们为域提供纯粹的接口,这些域被视为集合的单个入口点。我们称这些网关。

  • 最后,我们确定每个域都应该与其他域无关,也就是说,一个域不应该具有与其代码库或数据模型内部硬编码的另一个域相关的逻辑。由于团队经常需要在另一个团队的域中包含逻辑(例如,自定义验证逻辑或数据模型中的某些元上下文),因此我们提供了扩展架构,以支持该域中定义明确的扩展点。

换句话说,通过提供系统的体系结构(systematic architecture),域网关(domain gateways)和预定义的扩展点(predefined extension points),DOMA 打算将微服务体系结构从复杂的东西转变为可理解的东西:结构化的一组灵活,可重用和分层的组件。

实现方式

Domains

Uber 域代表一个或多个与逻辑功能分组绑定的微服务的集合。设计域时常见的问题是“域应该有多大?”在此我们不提供任何指导。有些域可以包含数十个服务,有些域只能包含一个服务。重要的任务是仔细考虑每个集合的逻辑角色。例如,我们的地图搜索服务构成一个领域,票价服务是一个领域,匹配平台(匹配骑手和驾驶员)是一个领域。这些也不总是遵循公司的组织结构。Uber Maps 组织本身分为三个域,在三个不同的网关后面有 80 个微服务。

Layer Design

层设计回答了“什么服务可以调用什么其他服务?”的问题。在 Uber 的微服务架构中。结果,我们可以将层设计视为“按比例分离关注点”。另外,我们可以将层设计视为“大规模依赖管理”。层设计描述了一种机制,用于考虑 Uber 跨服务依赖项的失败爆炸半径和产品特异性。当域从底层移到顶层时,它们在中断的情况下会影响较少的服务,并代表更多特定的产品使用案例。相反,底层的功能具有更多的依存关系,因此趋向于具有更大的爆炸半径,并代表了更通用的业务功能集。下图说明了此概念。

Layer

可以将顶层视为特定的用户体验(例如移动功能),并将底层视为通用的业务功能(例如帐户管理或市场旅行)。图层仅取决于其下的图层,这为我们提供了一种有用的启发式方法,可以考虑爆炸半径和区域集成之类的问题。值得注意的是,功能通常会将图表从特定的“向下”移到更一般的位置。可以想象一个简单的功能,随着需求的发展,该功能最终将越来越成为一种平台。实际上,这种向下迁移是可以预期的,而且 Uber 的许多核心业务平台都是从特定于车手或驾驶员的功能开始的,随着我们开发更多的业务线并且它们具有更多的依赖关系(例如 Uber Eats 或 Uber Freight),其功能变得更加普遍。

在 Uber 内部,我们建立了以下五个层次。

  • Infrastructure layer: 提供任何工程组织可以使用的功能。这是 Uber 对诸如存储或网络等重大工程问题的解答。

  • Business layer: 提供组织可以使用的 Uber 功能,但并非特定于特定产品类别或业务线(LOB)的功能,例如乘车,进餐或货运。

  • Product layer: 提供与特定产品类别或 LOB 相关但与移动应用程序无关的功能,例如由多个面向乘车应用程序使用的“请求乘车”逻辑(Rider,Rider“ Lite”,m.uber.com)等)。

  • Presentation: 提供直接与面向消费者的应用程序(移动/网络)中存在的功能相关的功能。

  • Edge Layer: 将 Uber 服务安全地暴露给外界。该层也支持移动应用程序。

如您所见,每个随后的层代表着越来越具体的功能分组,并且爆炸半径越来越小(或者换句话说,更少的组件取决于该层中的功能)。

Gateways

术语“Gateway API”已经是微服务架构中广泛建立的概念。我们的定义与已建立的定义没有太大的不同,只是我们倾向于将网关专门视为基础服务集合(我们称为域)的单个入口点。网关的成功取决于 API 设计的成功。

Gateways

由于上游使用者仅可在单一服务上运行,因此网关在将来的迁移,可发现性以及系统复杂性的整体降低方面提供了许多好处,因为上游服务只需要一个依赖关系,而不是对域中可能存在的几个下游服务的依赖关系。如果我们从面向对象设计的角度考虑网关,那么它们就是接口定义,它使我们能够根据底层“实现”(在本例中为底层微服务的集合)做我们想做的任何事情。

Extensions

扩展表示一种扩展域的机制。扩展的基本定义是,它提供了一种扩展基础服务功能的机制,而无需更改该服务的实际实现,也不会影响其整体可靠性。在 Uber,我们提供了两种不同的扩展模型:逻辑扩展和数据扩展。扩展的概念使我们能够将体系结构扩展为能够独立工作的多个团队。

Logic Extensions

逻辑扩展提供了一种扩展服务基础逻辑的机制。对于逻辑扩展,我们使用提供程序或插件模式的变体,以及基于逐个服务定义的接口。这样一来,扩展团队就可以以接口驱动的方式实现扩展逻辑,而无需修改基础平台的核心代码。