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