> For the complete documentation index, see [llms.txt](https://bohans.gitbook.io/ji-chu/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bohans.gitbook.io/ji-chu/spring/group-1/spring-cloud/wei-fu-wu-she-ji/jue-se-fen-pei/jia-gou-shi.md).

# 架构师

架构师在软件项目中的作用是**提供待解决问题的工作模型**。

架构师的工作是提供<mark style="color:blue;">**脚手架**</mark>，开发人员将根据这些脚手架构建他们的代码，使应用程序所有部件都组合在一起。

在构建微服务时，项目的架构师主要关注以下 3 个关键任务：

1. 分解业务问题
2. 建立服务粒度
3. 定义服务接口

### 分解业务问题

架构师将业务问题分解成<mark style="color:blue;">**代表离散活动领域的块**</mark>。这些块封装了与业务域特定部分相关联的业务规则和数据逻辑。

<mark style="color:blue;">**分离业务域是一门艺术，而不是非黑即白的科学**</mark>。你可以使用以下指导方针将业务问题识别和分解为备选的微服务：

* **描述业务问题，并注意你用来描述它的名词**。

  在描述问题时，反复使用的相同的<mark style="color:blue;">**名词**</mark>通常意味着它们是核心业务域并且适合创建微服务。
* **注意动词**。

  动词突出了动作，通常代表问题域的自然轮廓。如果发现自己说出“事务 X 需要从事物 A 和事物 B 获取数据”这样的话，通常表明多个服务正在起作用。
* **寻找数据内聚**。

  在将业务问题分解成离散的部分时，要寻找彼此高度相关的数据部分。如果在会话过程中，突然读取或更新与迄今为止所讨论的内容完全不同的数据，那么就可能还存在其他候选服务。<mark style="color:orange;">**微服务必须完全拥有它们的数据。**</mark>

### 建立服务粒度

一旦我们拥有了一个简化的**数据模型**，我们就可以开始定义在应用程序中需要哪些微服务。

<mark style="color:blue;">**从数据模型中提取服务需要的不只是将代码重新打包到单独的项目中，还需要梳理出服务要访问的实际数据库表，并且只允许每个服务访问其特定域中的表。**</mark>

将问题域分解成不同的部分后，我们通常会发现自己很难确定是否为服务划分了适当的<mark style="color:blue;">**粒度**</mark>级别。一个太粗粒度或太细粒度的微服务将具有很多的特征。<mark style="color:orange;">**当我们构建微服务架构时，粒度问题是至关重要的。**</mark>

* <mark style="color:orange;">**开始的时候可以让微服务涉及的范围更广泛一些，然后再重构到更小的服务**</mark>。在开始微服务旅程之初，很容易出现的一个极端情况就是将所有的东西都变成微服务。但是将问题域分解为小型的服务通常会导致过早的复杂性，因为微服务变成了细粒度的数据服务。
* <mark style="color:orange;">**重点关注服务如何相互交互**</mark>。这有助于建立问题域的粗粒度接口。**从粗粒度重构比从细粒度重构要更容易**。
* <mark style="color:orange;">**随着我们对问题域的理解的不断增长，服务的职责会随着时间的推移而改变**</mark>。通常来说，当需要新的应用功能时，微服务就会承担起职责。最初的单个微服务可能会发展为多个服务，原始的微服务则充当这些新服务的编排层，负责将应用的其他部分的功能封装起来。

> 如果微服务过于<mark style="color:orange;">**粗粒度**</mark>，可能会看到以下现象：
>
> * <mark style="color:orange;">**一个服务承担过多的职责**</mark>。服务中的业务逻辑的一般流程很复杂，并且似乎正在执行一组过于多样化的业务规则。
> * <mark style="color:orange;">**一个服务跨大量表来管理数据**</mark>。**如果你发现自己将数据持久化存储到多个表或接触到服务数据库以外的表，那么这就是一条服务过于粗粒度的线索**。我们喜欢使用这么一个指导方针：微服务拥有的表应该 3～5 个。再多一点，服务就可能承担了太多的职责。
> * <mark style="color:orange;">**一个服务的测试用例太多**</mark>。服务的规模和职责会随着时间的推移而增长。如果有一个服务，它一开始只有少量的测试用例，但最后却有数百个单元测试用例和集成测试用例，可能就需要重构。

> 如果微服务过于<mark style="color:orange;">**细粒度**</mark>，可能会看到以下现象：
>
> * <mark style="color:orange;">**问题域的一部分微服务像兔子一样繁殖**</mark>。如果一切都成为微服务，从服务中组合出业务逻辑就会变得既复杂又困难。这是因为完成一项工作所需的服务数量会急剧增长。一种常见的“坏味道”出现在应用程序有几十个微服务，并且每个服务只与一个数据库表进行交互时。
> * <mark style="color:orange;">**微服务彼此间严重相互依赖**</mark>。在问题域的某一部分中，微服务相互来回调用以完成单个用户请求。
> * <mark style="color:orange;">**微服务成为简单 CRUD（Create、Read、Update、Delete）服务的集合**</mark>。微服务是业务逻辑的表达，而不是数据源的抽象层。如果微服务除 CRUD 相关逻辑之外什么都不做，那么它们就可能过于细粒度了。

{% hint style="info" %}
应该通过<mark style="color:blue;">**演化思维过程**</mark>来开发微服务架构，在这个过程中，你知道不会第一次就得到正确的设计。这就是<mark style="color:blue;">**最好从一组较粗粒度的服务而不是一组细粒度的服务开始**</mark>的原因。

同样重要的是，<mark style="color:blue;">**不要对设计带有教条主义**</mark>。你可能会遇到服务的物理约束。例如，你需要创建一个将数据连接在一起的聚合服务，因为两个单独的服务之间交互会过于频繁，或者服务的域界线之间不存在明确的边界。

最后，要采取务实的做法来进行交付，而<mark style="color:blue;">**不是浪费时间试图让设计变得完美**</mark>，最终导致没有东西可以展现你的努力。
{% endhint %}

### 定义服务接口

架构师需要关心的最后一部分，是定义应用程序中的微服务该如何彼此交流。一般来说，可使用以下指导方针实现服务接口设计。

* <mark style="color:orange;">**拥抱 REST 的理念**</mark>。服务的 REST 方法本质上是将 **HTTP** 作为服务的调用协议，使用标准 HTTP 动词（GET、PUT、POST 和 DELETE）。围绕这些 HTTP 动词对基本行为进行建模。
* <mark style="color:orange;">**使用 URI 来传达意图**</mark>。用作服务端点的 URI 应**描述问题域中的不同资源**，并为问题域内的资源的关系提供一种基本机制。
* <mark style="color:orange;">**将 JSON 用于请求和响应**</mark>。JSON 是一种极其轻量级的数据序列化协议，比 XML 更容易使用。
* <mark style="color:orange;">**使用 HTTP 状态码来传达结果**</mark>。HTTP 协议具有丰富的标准响应代码，用于指示服务的成功或失败。学习这些状态码，最重要的是，在所有服务中始终如一地使用它们。

**所有这些指导方针都是为了完成一件事：使你的服务接口易于理解和使用**。你希望开发人员坐下来查看一下服务接口就能开始使用它们。如果微服务不容易使用，开发人员就会另辟道路，破坏架构的意图。
