微服务并不是孤立存在的,它们存在于一个环境里,微服务在这个环境里进行交互。把这种环境看成微服务生态系统并分层,有助于理解微服务架构。
在一个设计良好的微服务生态系统里,微服务与基础设施之间是分离的。微服务与硬件、网络、构建和部署管道、服务发现和负载均衡都是分离的。它们都是微服务生态系统基础设施的组成部分。如何以一种稳定可靠的、可伸缩的、可容错的方式来构建、维护和标准化基础设施,是微服务运维的根本。
基础设施必须能够支撑微服务生态系统。基础设施工程师和架构师的共同目标是为微服务的开发工作隐藏底层的运维细节,并构建一个稳定的、可伸缩的基础设施平台,让开发者可以轻松地在上面构建和运行微服务。在一个稳定的微服务生态系统里开发一个微服务应该跟开发一个小型的标准应用一样,都需要一个出类拔萃的基础设施的支持。
微服务生态系统可以被分为4 层,虽然层与层之间的边界不一定都很清晰,但这些层会涉及基础设施的几个元素。底下的3 层是基础设施层:最下面的是硬件层,其次是通信层(一直渗透到第4 层),紧接着的是应用平台层。第4 层(顶层)就是微服务所在的层。
微服务生态系统的4层模型
第1 层:硬件层
微服务生态系统的底层是硬件层。这一层是服务器物理机所在的层,它们是所有内部工具和微服务运行的基础。这些服务器被放置在数据中心的机架上,由供电系统供给电力,使用着昂贵的HVAC 冷却系统。这里有各种各样的服务器:有些专门用于运行数据库,有些专门处理CPU 密集的任务。它们有些是某些公司私有的,有些是从所谓的“云服务提供商”那里租来的,比如Amazon Web Services Elastic Compute Cloud(AWS EC2)、Google Cloud Platform(GCP)或Microsoft Azure。
硬件的选择取决于服务器的所有者。如果你的公司有自己的数据中心,硬件的选择就是自己的事情,完全可以根据实际需要来定制服务器。如果你的服务器是在云端(这种情况比较普遍),你就没有太多的选择余地。是自己购买服务器还是选择云服务并不是一个简单的选择题,它需要考虑购买成本、可用性、可靠性和运营成本。
管理服务器是硬件层的职责之一。每台服务器都需要安装标准的操作系统。使用哪种操作系统并没有一个标准的答案,这完全取决于你要构建的应用程序、构建应用程序所使用的编程语言以及构建微服务所需要的软件包和工具。主流的微服务生态系统一般会使用Linux 的变形版本,比如CentOS、Debian 或Ubuntu,不过一个使用了.NET 平台的公司显然会有不同的选择。硬件层之上还可以有一些层,比如资源隔离、资源抽象(由Docker 和Apache Mesos 提供的)和数据库(专门的或共享的)。
操作系统的安装和硬件资源的配置是服务器的第一个层。每个主机必须被配置好,而且在安装好操作系统之后,必须提供一个配置管理工具(比如Ansible、Chef 或Puppet)来安装应用程序,并做好必要的配置。
对主机进行主机级别的监控(使用Nagios)是有必要的,而且需要记录主机级别的日志。在主机出现异常(磁盘错误、网络错误或CPU 过载)时就可以方便地对它们进行诊断,有助于问题的解决。
==硬件层的主要内容==
微服务生态系统的硬件层(第1 层)包含:
- 物理服务器(公司自有或从云服务提供商那里租用)
- 数据库(专有的或共享的)
- 操作系统
- 资源隔离和资源抽象
- 配置管理
- 主机级别的监控
- 主机级别的日志
第2 层:通信层
微服务生态系统的第2 层是通信层。通信层渗透到生态系统的所有层(包括应用平台层和微服务层),因为微服务之间的交互会在多个层上进行,所以很难清晰地对通信层与其他层之间的边界进行定义。虽然难以清晰地定义它们之间的边界,但是这个层所涉及的元素是很明确的。第2 层一般包含网络、DNS、RPC 和API 端点、服务发现、服务注册以及负载均衡。
有关通信层网络和DNS 元素的内容已经超出了本文的范畴,在这里,我们主要讨论RPC、API 端点、服务发现、服务注册和负载均衡。
RPC、端点和消息传递
微服务通过远程过程调用(RPC)或消息传送与其他微服务进行交互,这些调用通过网络发送到其他微服务的API 端点上(如果使用的是消息传递,消息会被发送到消息代理,消息代理会对这些消息进行路由)。基本原理是这样的:使用一个特定的协议,一个微服务把符合特定格式的数据通过网络发送到另一个服务(或者是另一个微服务的API 端点)或消息代理上(消息代理确保数据会被路由到其他微服务的API 端点上)。
微服务有几种通信方式,第一种是最常用的HTTP+REST/Thrift。如果使用的是这种方式,各个服务使用超文本传输协议(HTTP)进行网络交互,它们向特定的REST 端点(使用各种HTTP 方法,比如GET、POST 等)或Thrift 端点发送请求或从这些端点接收响应。发送的数据一般是JSON(或protocol buffer)格式。
HTTP+REST 是最便利的微服务通信方式。它使用起来很简单,而且稳定可靠。不过它的不足之处在于它是同步(阻塞)的。
第二种通信方式是消息传递。消息传递是异步(非阻塞)的,不过相对复杂。消息传递的工作原理是这样的:一个微服务把数据(消息)通过网络(HTTP 或其他)发送给一个消息代理,消息代理会把消息路由到其他微服务上。
消息传递也有几种模式,最流行的两种分别是发布和订阅以及请求和响应。如果使用的是发布和订阅模式,客户端会订阅一个主题,它将从主题上收到发布者发布的任何一个消息。请求和响应模式就更直接了,客户端发送一个请求到一个服务(或消息代理)上,这个服务会对这个请求做出响应。有些消息中间件同时支持两种模式,比如ApacheKafka。Celery 和Redis(或Celery 和RabbitMQ)可以为Python 微服务传送消息(并处理任务):Celery 处理任务或消息,Redis 或RabbitMQ 作为消息代理。
消息传递有几个缺点需要注意。消息传递不会比HTTP+REST 具备更强的伸缩性,如果你的系统对伸缩性有要求的话一定要清楚这一点。消息传递对变更不友好,因为它是集中式的,这样会导致消息队列和消息代理变成整个生态系统的故障点。它的异步特性在并发环境里会导致竞赛条件,如果没有处理好,还会出现无限循环。在使用消息传递时,如果能够处理好上述这些问题,它会变得跟同步解决方案同样稳定和高效。
服务发现、服务注册和负载均衡
在单体应用架构里,所有的业务流量都被发送给负载均衡器,然后被分发到应用服务器上。而在微服务架构里,业务流量被路由到大量不同的应用程序上,然后再被分发给部署了特定微服务的服务器。为了能够高效地实现上述场景,微服务架构需要在通信层实现三项技术:服务发现、服务注册和负载均衡。
一般来说,如果微服务A 需要向微服务B 发起请求,那么微服务A 需要知道微服务B 的IP 地址和端口。微服务的通信层需要知道这些微服务的IP 地址和端口,才能正确地路由这些请求。这个问题可以通过服务发现(比如etcd、Consul、Hyperbahn 或ZooKeeper)来解决,服务发现可以确保请求会被路由到它们本该去的地方,而且只会被路由到正常运行的实例上(这非常重要)。服务发现需要用到服务注册,服务注册中记录了生态系统里所有微服务的IP 地址和端口。
动态伸缩和端口分配
在微服务架构里,在对微服务进行横向扩展和重新部署时(比如使用了像Apache Mesos 这样的硬件抽象层),端口和IP 地址会发生变化。在这种情况下,可以考虑为每个微服务分配一个静态端口(包括前端和后端)。
除非你的所有微服务都部署在同一个实例上(一般不太可能),否则需要在通信层使用负载均衡。简单地说,负载均衡可以做到:如果你有10 个微服务实例,负载均衡器(软件或硬件)可以确保业务流量被(均衡地)分发到所有的实例上。在微服务生态系统里,只要涉及请求转发,都需要用到负载均衡器,这意味着一个大型的微服务生态系统将包含多层负载均衡。常见的负载均衡器有Amazon Web Services Elastic Load Balancer、Netflix 的Eureka、HAProxy 和Nginx。
==通信层的主要内容==
微服务生态系统的通信层(第2 层)包含:
- 网络
- DNS
- 远程过程调用(RPC)
- 端点
- 消息传递
- 服务发现
- 服务注册
- 负载均衡
第3 层:应用平台层
应用平台层是微服务生态系统的第3 层,这一层包含了所有独立于微服务的内部工具和服务。这一层所包含的集中式的工具和服务跨越了整个生态系统,因为有了这些工具和服务,微服务开发团队就可以把精力集中在微服务的开发上。
一个好的应用平台需要为开发者提供一套内部的自助工具,包括标准化的开发流程、集中式的自动化构建和发布系统、自动化测试、标准化和集中式的部署方案以及集中式的日志和微服务级别的监控。这些元素的细节此处不进行探讨,不过我们也会简要地介绍其中的几个元素,阐述一些基本的概念。
内部自助开发工具
有很多东西可以被纳入内部自助开发工具的范畴,它们是否可以被归为这类工具不仅取决于开发者对工具的需求,还要考虑基础设施和生态系统的整体抽象度和复杂性。决定使用哪一种工具,首先要对责任领域进行切分,然后对开发者所要完成的任务进行评估,以便设计、构建和维护他们的服务。
在一个已经使用了微服务架构的公司里,给工程团队指派职责要十分谨慎。最简单的做法是为微服务生态系统的每一个层组建一个工程子团队。这些工程子团队将负责处理它们所在层的所有相关事务:运维团队负责第1 层,基础设施团队负责第2 层,应用平台团队负责第3 层,微服务团队负责第4 层(这看起来很简单,只要你能明白就好了)。
在这种组织结构里,工作在上层的工程师需要使用自助工具对下层的一些东西进行配置。例如,负责消息服务的团队应该为其他开发者提供一个自助工具,当微服务团队的开发者需要为他们的服务配置消息系统时,他们就可以使用这个工具,而无须过多地了解纷繁复杂的消息系统。
使用这些集中式的自助工具是有原因的。在一个多元化的微服务生态系统里,一个团队的普通工程师对其他团队的系统和服务并不了解(或知之甚少),他们也不可能成为面面俱到的专家。每个开发人员只对自己负责的部分比较了解,但从整个生态系统来看,这些开发人员组合在一起就无所不知了。为生态系统的每一部分构建易用的用户界面,为开发人员提供相关的培训,以便教会他们如何使用这些工具,而不是试图让每个开发人员了解这些工具和服务纷繁复杂的内部细节。把所有的事情放到一个黑匣子里,然后提供详细的说明文档。
使用这些工具的第二个理由是,你不需要其他团队的人来对你的服务和系统做任何关键性的改动,因为这些人可能会给你们带来麻烦。对于底层(第1 层、第2 层和第3 层)的服务和系统来说,更是如此。让他们在这些层上面做出改动,或者要求(更糟糕的是期待)他们成为某方面的专家有可能会酿成大祸。举一个配置管理的例子:不具备相关专门知识的微服务团队开发人员对系统配置做了一些变更,这有可能导致大规模的服务瘫痪,因为他们所做的变更有可能不只是影响到他们自己的服务。
开发周期
开发人员在对已有微服务进行修改或构建新的微服务时,对开发流程进行流水线化、标准化和自动化可以大幅提升开发效率。对开发流程进行标准化将在第4 章进行探讨。有些东西需要被放在微服务生态系统的第3 层,让稳定可靠的开发成为可能。
首先是集中式的版本控制系统,这个系统保存了所有代码,允许对代码进行跟踪、版本管理和搜索。这个可以通过一些工具来实现,比如GitHub 或者自有的git 或svn 代码仓库,可以将这些仓库和一些协作工具集成起来,比如Phabrictor,以简化代码的维护和审查工作。
其次是稳定高效的开发环境。众所周知,在微服务生态系统里实现一个这样的开发环境是很困难的,因为微服务之间的依赖太过复杂。不过它们都是最基本的因素,我们无法避免。一些工程组织倾向于在本地完成开发工作(在开发人员的电脑上),不过这样会导致糟糕的部署,因为开发人员并不清楚他们修改的代码是如何被部署到生产环境的。最稳定可靠的构建开发环境的方式是为生产环境创建一个镜像(不是为了预生产,也不是为了收集反馈,更不是为了生产),这个镜像包含所有复杂的依赖关系链。
测试、构建、打包和发布
开发过程中的测试、构建、打包和发布应该尽量被标准化和集中化。在开发结束之后,当有代码变更被提交,需要运行相关的测试用例,然后自动构建和打包即将发布的新版本。这个时候,持续集成工具就可以派上用场,一些现成的解决方案(比如Jenkins)不仅功能齐全而且使用方便。这些工具可以让整个过程自动化,几乎不留给人类任何犯错的机会。
部署管道
在经过了开发、测试、构建、打包和发布这些步骤之后,部署管道是新代码走向生产环境的另一个流程。在一个微服务生态系统里,部署会在很短的时间内变得极其复杂,每天上百个部署都是很平常的事。开发团队需要为开发构建工具,并对开发过程进行标准化。
日志和监控
所有的微服务都应该把与它们的请求和响应相关的重要信息记录到日志里。因为微服务变更的速度太快,如果系统发生了错误,重建当时的系统状态变得很困难,导致代码的缺陷难以重现。使用微服务级别的日志可以帮助开发人员更好地了解他们的服务在过去某个时刻或当前时刻的状态。在微服务级别对微服务的关键度量指标进行监控也是出于同样的目的:实时准确的监控可以帮助开发人员了解服务的状态和健康状况。
微服务生态系统的应用平台层(第3 层)包含:
- 内部自助开发工具
- 开发环境
- 测试、构建、打包和发布工具
- 部署管道
- 微服务级别的日志
- 微服务级别的监控
第4 层:微服务层
微服务生态系统的顶层是微服务层(第4 层)。这一层是微服务以及微服务所有相关事物所在的层,它与底下的基础设施层完全分离,比如硬件、部署、服务发现、负载均衡和通信。微服务层唯一没有被分离的是使用自助工具所做的配置。
在软件工程里,应用的配置一般会被集中化,针对某个工具或某些工具(配置管理、资源隔离或部署工具)的配置可以和这些工具保存在一起。例如,应用程序的自定义部署配置一般会和部署工具的代码保存在一起,而不是和应用程序的代码保存在一起。这种方式对单体应用架构或小型的微服务生态系统来说是没有问题的,但在包含了大量微服务和内部工具(每个工具都有自定义的配置)的大型微服务生态系统里,这种方式就会造成混乱:处在上层的微服务团队需要修改处在下层的工具代码,他们会经常忘记哪些地方包含了配置信息(或者不包含)。为了解决这个问题,可以把与微服务相关的配置放在微服务代码库里,然后开放给下层的工具和系统访问。
==微服务层的主要内容==
微服务生态系统的微服务层(第4 层)包含:
- 微服务
- 微服务相关的配置
本文选自《生产微服务》,点此链接可在博文视点官网查看此书。
想及时获得更多精彩文章,可在微信中搜索“博文视点”或者扫描下方二维码并关注。