第1章 预备知识

本章将概述微服务的概念。1.1节明确了微服务的定义。1.2节回答了“为什么采用微服务”这个问题。1.3节探讨了与微服务相关的挑战。

1.1 微服务概述

本书关注的重点是微服务——一种实现软件模块化的方案。模块化并不是什么新概念。一直以来,我们都将大型系统划分成小模块,以便于软件的实现、理解以及后续开发。

微服务是一种新的模块化方法,但“微服务”一词却没有明确的定义,因此本章就从该词的定义出发,阐述微服务与一般的单体部署(deployment monolith)① 之间的区别。

微服务定义初探

与单体部署不同的是,构成微服务的模块是以独立进程的形式运行的。这种方式源于UNIX思想,该思想可简述为如下三点。

 一个程序应该仅完成一个任务,且应该完美地完成该任务。

 程序之间应该能够协同工作。

 程序之间应该提供一个通用的接口。在UNIX中,这个通用接口就是文本流。

微服务一词没有固定的定义。第3章将会提供更详细的定义。但以下标准可以作为微服务的基本概念。

 微服务是一个模块化的概念。采用微服务是为了将大型软件系统分成更小的部分,从而影响团队的组织和软件系统的开发。

 微服务能相互独立地部署。一个微服务内部的变动不会影响其他微服务在生产环境下的部署。

 微服务能基于不同技术来实现。各个微服务不局限于特定的编程语言或平台。

 微服务拥有各自独立的数据存储:可以是私有的数据库,也可以是共享数据库中一个完全隔离的模式(schema)。

 微服务可以自带支持服务,例如搜索引擎或特定的数据库。当然,所有微服务可以共享一个公共平台,例如虚拟机。

 微服务是自包含(self-contained)的进程或虚拟机(例如支持服务包含在虚拟机内)。

 微服务间必须通过网络通信。为此,微服务采用支持松耦合的协议,例如REST或消息机制。

单体部署

微服务的反面是单体部署。单体部署指的是只能部署成一整块的大型软件系统。单体部署必须作为一个整体通过持续交付流水线的所有流程,如开发、测试和发布。由于单体部署太大,它花费在这些流程上的时间远远超出小型系统。这降低了系统的灵活性,却增加了流程的成本。虽然单体部署的内部结构也可以模块化,但所有模块必须同时部署到生产环境。

① 作者强调deployment monolith(单体部署)是为了区分于所谓的module monolith(所有代码放在同一个代码库中)以及runtime monolith(系统以单一应用或进程的形式运行)。——译者注

1.2 为什么采用微服务

微服务架构允许软件分成模块,使软件的修改更容易。

如图1-1所示,微服务有许多显著的优势。

图像说明文字

模块化强

微服务是一种模块化很强的理念。系统如果由多个软件组件构成,例如多个Ruby GEM包、Java JAR包、.NET程序集、Node.js NPM包,就容易混进一些不必要的依赖。举例来说,假设有人在某个预期之外的地方引用了一个类或方法,这就产生了对该类或方法的一个依赖,但该类或方法的开发人员并不知情。开发人员对这个类或方法的任何修改,都可能会意外地导致系统另外一部分出错。这样的依赖会越来越多,问题也会越来越严重,甚至会导致系统无法继续运行或开发。

相反,微服务之间只通过消息、REST等机制实现的显式接口相互通信,因此调用一个微服务要克服更高的技术障碍,从而降低了引入不必要依赖的可能性。原则上来说,单体部署软件也可以实现高层次的模块化。但实践经验告诉我们,单体部署架构会随时间而腐化。

可替代性强

与单体部署的模块相比,微服务更易于替代。其他组件通过显式接口来使用微服务。如果一个新的微服务所提供的接口和已有的微服务一样,那么它就能替代旧的那个。新的微服务可以在不同的代码库中实现,甚至采用不同的技术,只需提供一致的接口即可。这在传统的系统中通常是不可能实现或很难实现的。

小型的微服务更容易替代。开发软件系统时,开发人员通常会忽视未来更换代码的需求。谁会考虑开发中的系统在未来可能被取代呢?微服务的可替代性降低了错误决策的代价。如果技术或方案的选择仅局限于某个微服务,那么必要的时候可以采用其他技术或方案重新实现这个微服务。

可持续开发

微服务模块化强以及容易替代的特点,使软件开发可以持续进行。开发新项目通常是最简单的,但项目时间越长,生产效率就越低,一个重要的原因就是软件架构的腐化。微服务通过加强模块化来对抗软件的腐化。绑定技术过时以及难以移除旧的系统模块,都是阻碍单体部署持续开发的问题。微服务架构不绑定任何特定技术,可以通过对微服务逐个替代的方式来解决这些问题。

遗留应用的进一步开发

在开发遗留系统时,采用微服务架构是比较简单的:新功能在微服务中实现,无须将新功能加入到难以理解的遗留代码库,因此能够取得立竿见影的效果。新加入的微服务可以只响应特定的请求,其余的请求则转交给遗留系统来处理,转交之前还可以对请求进行处理。这样就不需要彻底更换遗留系统。另外,微服务可以用新技术来开发,不会被遗留系统的技术栈所束缚。

上市时间

微服务能缩短项目的上市时间。如前所述,微服务能够逐个部署到生产环境。假设在某大型系统中,每个团队负责一个或多个微服务,且功能的实现只需修改其负责的微服务,那么各个团队就能够并行开发,而且功能部署到生产环境的过程中,也不需要与其他团队费时费力地进行沟通协调。因此,与单体部署相比,微服务可让多个团队并行开发更多的功能,并在更短时间内将其部署到生产环境。微服务架构将大团队划分为小团队,小团队分别负责各自的微服务开发,这有助于改进团队的敏捷过程。

独立伸缩性

每个微服务可以独立于其他服务进行伸缩(scale)。如果只有一小部分功能被频繁调用,那么只需对这部分功能进行扩容即可。这能极大地简化基础设施和运维工作。

自由选择技术

采用微服务架构进行开发时,不会限制具体采用的技术。这使得微服务架构能在单个微服务内测试新技术,而不会影响其他服务。由于引入的新技术或原有技术的新版本仅在受限的环境中被采用,测试风险会更小。微服务还能采用特定技术来实现特定功能,例如选择特定的数据库。如果出现问题,那么可以很轻松地替换或撤销微服务,因此风险相对较低。此外,新技术仅局限在单个或少数微服务中,因此降低了采用新技术的风险,并可以在不同的微服务上采用不同的技术。这使得尝试和评估新技术变得更容易,同时有助于提升开发人员的生产效率,避免技术平台落伍,还能吸引高水平的开发人员。

持续交付

微服务有利于持续交付。微服务很小,因而能简化持续交付流水线的实现。微服务能独立部署,部署一个微服务的风险低于一个单体部署系统。保证微服务的安全部署也更容易,例如可并行运行多个不同版本。对很多开发人员来说,便于持续交付是他们采用微服务的主要原因。

以上都是采用微服务的有力依据。哪个原因更重要则由具体情况而定。从业务角度考虑,改进敏捷过程和持续交付通常都很关键。第4章将详细分析微服务的优势及其优先级。

1.3 挑战

凡事都有两面性。第5章会论述引入微服务所带来的挑战,以及如何应对这些挑战。简而言之,主要的挑战如下。

 隐藏的关系。系统架构由服务之间的关系构成,但微服务之间的调用关系并不清晰,这增加了架构工作的挑战性。

 不易重构。太强的模块化导致微服务不易重构,因此微服务之间的功能转移会比较困难。采用微服务后就很难改变系统的模块结构。幸好,有一些技巧能够减少这样的问题。

 领域架构的重要性。将领域模块化并划分到各个微服务中是很重要的,因为这将决定团队的分工情况。领域架构层面的问题也影响着团队组织,只有稳定的领域架构才能保证微服务开发的独立性。模块化建立起来后就比较难改动,因此后面一旦出现错误就很难修正。

 微服务运行的复杂性。微服务系统需要部署、控制和运行许多的组件。这增加了运维的复杂性,以及系统运行所需的基础设施。微服务需要实现运维自动化,以免运维变得费时费力。

 分布式系统的复杂性。基于微服务的系统是一个分布式系统,这意味着开发人员将面对更高的复杂性。与进程内的调用相比,网络调用较慢,带宽也更小,因此微服务之间的调用可能会因网络问题而失败。

1.4 总结

本章概述了微服务的概念。本章从微服务的定义开始,回答了“为什么采用微服务”的问题,最后讨论了微服务相关的挑战。

目录

  • 前言
  • 第一部分 动机和基础知识
  • 第1章 预备知识
  • 第2章 微服务应用案例
  • 第二部分 微服务是什么,用还是不用
  • 第3章 什么是微服务
  • 第4章 采用微服务的原因
  • 第5章 挑战
  • 第6章 微服务与SOA
  • 第三部分 微服务的实现
  • 第7章 微服务系统架构
  • 第8章 集成与通信
  • 第9章 单个微服务架构
  • 第10章 微服务与微服务系统的测试
  • 第11章 微服务的运维及持续交付
  • 第12章 微服务架构的组织效应
  • 第四部分 技术
  • 第13章 微服务架构示例 
  • 第14章 纳米服务技术
  • 第15章 把微服务用起来