拆分BookSwap单体应用
本章的讨论主要围绕微服务架构展开,因为分布式系统已成为标准,并且在不久的将来,你很可能会在这种系统上工作。然而,BookSwap 应用程序目前仍然是一个单体应用程序。基于我们在第 7 章《Go语言中的重构》中讨论的一些实践,我们可以探讨如何拆分 BookSwap 单体应用。图8.7 展示了一些我们可以创建的微服务。

分布式 BookSwap 系统的微服务具有明确的职责:
-
SwapService 是系统的入口点,负责处理和路由所有传入的用户请求。它直接依赖于 BookService 和 UserService,这两个服务拥有 SwapService 所依赖的数据。
-
UserService 负责所有与用户管理相关的操作。该服务拥有持久化存储 UsersDB,并在系统内对其拥有完全控制权。这种存储可以采取任何形式,但服务必须能够支持 SwapService 所需的访问模式。该服务直接依赖于 BookService。
-
BookService 负责所有与图书管理相关的操作。该服务拥有自己专用的持久化存储 BooksDB,并在系统内对其拥有完全控制权。该服务直接依赖于 PostingService,这是 BookSwap 系统外部的服务。
避免共享数据库
BookService 和 UserService 被设计为拥有各自的专用数据库,而不是共享一个持久化存储。这使得我们能够强制执行两个微服务之间的数据分离,并确保数据库故障不会导致两个服务同时中断。 |
图8.7 中的简单 BookSwap 系统是我们拆分 BookSwap 单体应用的起点。正如我们所看到的,这些服务之间存在依赖关系,因此它们必须支持其消费者所需的访问模式。拆分单体应用的下一步是设计不同服务的 API。
图8.8 展示了这些服务可能暴露的 API 调用:

如前所述,SwapService 是唯一面向用户的服务,其他服务都是它的直接依赖项。我们可以看到 BookSwap 服务中不同领域的以下访问模式:
-
图书 通过其主键 ID 和所有者用户 ID 进行访问。必须实现这种基于两个索引的访问模式,以满足 SwapService 的需求。
-
用户和图书之间存在一对多关系。如果我们使用 SQL 数据库,那么用户 ID 是图书表的外键。这种类型的依赖关系也可以在 NoSQL 表中实现,尽管它更自然地适合 SQL 数据库。
-
用户 的创建和更新是通过对相应端点的相同 POST 请求完成的。这符合 RESTful 设计实践,但这种合并操作应在服务层更低的位置处理。
-
图书 通过 POST 请求创建,但通过其 ID 作为 URL 参数进行更新。第二次更新是交换端点的实现。
这些简单的访问模式可以很容易地通过 SQL 或 NoSQL 持久化存储解决方案实现。强烈建议 REST 端点使用 JSON 作为内容类型,尤其是因为 Go 的 encoding/json
库原生支持 JSON 的编组和解组。我们之前已经探讨了使用 PostgreSQL 进行持久化存储,但大多数主流的 NoSQL 数据存储都有 Go 驱动程序。
到目前为止,BookSwap 单体应用程序可能一直存在于一个单一的代码库中,使开发人员能够完全了解应用程序的所有更改。然而,在微服务世界中,每个服务都有自己的代码仓库和团队所有权。
图8.9 展示了新微服务架构中暴露的五种服务集成:

微服务根据数据流和两个服务之间的请求流承担消费者和提供者的角色:
-
客户端代码 是消费者,它向 SwapService 发出请求,SwapService 通过依赖 BookSwap 应用程序的其他服务来处理这些请求。
-
SwapService 是消费者,因为它向 BookService 和 UserService 发出请求,以处理创建和更新其相应模型的操作。
-
UserService 是消费者,而 BookService 是提供者,因为 BookService 获取属于用户的图书列表。
-
BookService 是消费者,而外部的 PostingService 是提供者,因为 PostingService 处理所有图书交换的副作用,这是一个至关重要的细节,因为这些副作用在现实世界中提供了系统的商业价值。
对 BookService 和外部 PostingService 之间的集成进行 契约测试,可以帮助我们验证版本升级,确保外部 API 继续与我们的系统良好集成。这是确保系统及其所有依赖项持续成功运行的好方法。
正如我们在本节中的 BookSwap 应用程序中所看到的,一旦领域和团队具备足够的成熟度来承担这一任务,单体应用程序就可以转换为微服务架构。这反过来又为开发、测试和发布过程增加了不同类型的复杂性。而这种复杂性则使解决方案和团队能够进一步扩展。一个坚实的测试策略,包括契约测试,可以帮助验证微服务架构的稳定性和可扩展性。