1、微服务架构兴起的原因
互联网时代,在极端情况下,每天都有新需求要开发上线。随着代码量及团队成员的增加, 传统单体式架构的弊端日益凸显,严重制约了业务的快速创新和敏捷交付,与互联网所追求的 “唯快不破”的目标越来越远。这就是微服务架构兴起的时代大背景。
微服务架构( Microservice Architecture) 是近两年来最流行的架构术语之一,大名鼎鼎的 Martin Flower曾这样描述它:
“微服务”只不过是满大街充斥的软件架构中的一个新名词而已。尽管我们非常鄙视这样的东西,但其所描述的软件风格越来越引起我们的注意。在过去几年里,我们发现越来越多的项目开始使用这种风格,以至于我们身边的同事在构建企业级应用时,理所当然地认为这是一种默认开发形式。然而 ,很不幸,微服务风格是什么,应该怎么开发,关于这样的理论描述却很难找到。
为什么微服务架构会如此快速地流行?为什么越来越多的人理所当然地认为微服务架构是一种默认的开发形式?
为了弄明白上面两个问题,我们需要先弄明白另外两个基本问题,即我们通常讲的架构是怎样一种架构,而微服务架构又是怎样一种架构?下面这张图给出了两者间的区别与对比。传统的应用架构又称为单体应用(Monolithic), 表现为业务系统的各个模块是紧耦合的关系,各模块运行在一个进程中,每次升级系统基本上都要重启整个应用进程,如果某个模块有问题,则可能导致整个系统无法正常启动。而微服务架构则是将业务系统中的不同模块以安装微服务的方式进行拆分,每个微服务变成一个独立的Project,独立编译并且部署为一个独立的进程, 每个微服务都可以部署多个独立的进程对外提供服务,对外的接口方式通常是REST或 者RPC, 此外,不同的微服务进程可以部署到多个服务器上。我们通过对比就会发现,微服务架构通过将一个庞大的单体进程分解为相互独立的多个微小进程,以分布式的思想巧妙解决了传统单体 应用在互联网时代遭遇的各种问题。所以微服务架构这种新的理念被大家快速接受并且迅速流 行,是有深刻原因的。
为了解决传统的单体架构面临的挑战,软件架构先后演出了SOA架构、RPC架构、分布式服务框架,最后进化为微服务架构。但我们需要牢记一点:软件开发从来不存在银弹,因此微服务架构也不是银弹,它更多是一种架构思想与开发模式的改变,而在具体的实施过程中还存在大量的技术问题及团队问题需要妥善解决。
微服务架构实施过程中所面临的最大的一个技术问题就是开发运维过程中的自动化。假如我们要把原来某个中等规模的系统改造为微服务架构,则最少也能拆分出十几个微服务,于是这么多微服务进程的编译、部署、调测及升级就演化成一个浩大的工程了,如果没有自动化的手段,则微服务化这种劳民伤财的事情恐怕是没有人愿意去推动的。说到自动化,就不得不提容器技术,它是促进微服务架构发展的得力功臣,也是微服务架构得以快速流行的第二个重要原因。
2、容器技术
容器技术其实很早就被一些互联网公司广泛使用了,早在Docker兴起前的十几年内,Google就一直采用容器技术支撑着世界上最大的分布式集群,只是一直对外保守秘密,外界无从知晓,Google直到祭出容器之上的微服务架构神器Kubemetes后,才首次对业界公布了这个保守了几十年的最大秘密。Google之所以开源自己的王牌技术,原因之一是容器技术己经被业界公认为IT 界最重要的平台级技术,如果不能抢占先机和掌握话语权,就会逐步失去技术领先 性所带来的市场份额。
我们先来回顾容器技术的代言人— Docker的发展历史。Docker直到 2014年才发布1.0 版本,但就在那年,Docker的声势就达到了前所未有的程度:它被爱好者冠以“云计算新星”“下一代虚拟机”等称号,成为2014年最热门的技术之一。从 2014年年初的B轮融资到该年年末的 DockerCon欧洲大会,Docker在这一年里顺风顺水,就连微软、Google、AWS这样的巨头也敬它 三分,彼时,微服务架构、云计算、DevOps等技术理念如日中天,而 Docker恰恰可以完美地从技术上驱动这些概念落地,加速这些理念的实施。2015年爆发了容器技术史上最重要的战争一分裂之战,那年CoreOS发布了自己的容器引擎Rocket,引发容器技术的分裂与统一的大争论,随后在 Linux基金会的干预下,Docker公司与CoreOS公司握手言和,成立了 OCI(Open Container Initiative) 标准委员会,它类似当年Java的JCP组织,参与者包括Google、RedHat等巨头,OCI组织负责制定与领导容器技术标准规范,2016年发布的Docker1.11成为第一个符合OCI标准的容器引擎。从2014年到2016年的两年时间里,Docker经历了指数级的增长,DockerHub的下载量从1亿增加到60亿。而2017年最大的事件莫过于Docker公司开始将Docker的版本区分为企业版和社区版,开始面向企业收费,随后又将Docker开源项目的代码迁移到新的Moby项目上。
我们知道,在软件开发过程中有很多环节是靠人工的,比如搭建环境、发布安装包(发布安装包到某个FTP服务器上或者以U盘方式复制)、部署应用、升级系统等,这些过程都比较耗时耗力,很难保证任务的质量与完成时间。在分布式系统的情况下,一旦集群上了规模,上述人工操作极易因为大量重复性的劳动而导致各种难以排查的错误。Docker公司敏锐地察觉到了传统软件开发中的上述痛点问题,以创新性的标准化镜像(Docker Image)打包发布应用技术为突破口,成功地定义了 “软件生命周期中的标准化与自动化”的新标准。下面这张图给出了Docker的标准化镜像的示意图。
Docker镜像是一个包含了目标程序所有依赖文件的一个“All in one”的分层压缩包,你可以认为它是一个没有Linux内核但有Linux文件系统和基础命令的一个最精简版虚机,这个虚机里包括了己经安装和配置好的目标应用二进制代码,以及运行目标程序中的所有其他依赖包, 比如一个运行在Tomcat中的完整应用的Docker镜像组成如下。
而启动镜像的过程就是启动打包制作镜像时指定的目标程序,比如对于Tomcat来说,就是运行tomcat.sh命令,此外由于镜像本身已经固化了安装过程及配置参数,所以Docker镜像创建和启动一个容器就变成了一个非常简单并且不会出错的命令:
docker run xxximage
而运行期间需要指定的参数可以通过环境变量及启动命令的参数等方式传递到容器中,不同的容器之间相互隔离,因此你可以在一个主机上同时启动不同镜像版本的多个版本的容器并测试信息。更进一步地,Docker将制作镜像(build image)、创建容器,以及启动、停止、挂起、恢复、销毁容器的所有功能都做成了 REST API, 于是我们可以使用编程的方式来实现自动化控制能力,后面提到的Kubemetes即采用了Docker的API来实现了全自动的微服务架构平台。
打包好的Docker镜像是否可以像源码一样能够进行版本管理、集中托管并且被全球任意联网的机器下载运行呢? Docker公司的第二个创意就模仿了GitHiib的做法,创建了全球唯一的开放性 Docker仓库一 Docker Hub, 任何组织和个人都可以注册账号,并且分享自己打包的 Docker镜像,现在你所能想到的任何中间件或基础应用几乎都在Docker Hub上存在镜像,比如下面这句命令就自动从Docker Hub拉下来一个MySQL镜像,并且在本机启动了一个MySQL 服务器,可以让远程机器访问。正是Docker Hub的存在大大加速了 Docker技术的普及和发展。
docker run -it -e MYSQL_ROOT_PASSWORD-123456 mysql/mysql-server
私有的镜像仓库被称为Docker Registry,通常每个使用Docker的公司都需要自己建立一个私有的Docker Registry,存放从Docker Hub拉取的标准基础镜像,以及基于这些基础镜像而打包的私有镜像。下图给出了Docker镜像打包、运行过程中与Docker Registry之间的交互过程。
综上所述,我们通过Docker技术可以很容易地将软件开发从源码编译、镜像打包、测试环境部署、版本发布、系统升级到生产环境发布等生命周期中的所有重要环节自动化,这是加速微服务架构实施的重要技术保障手段。
3、如何理解微服务架构
在前面讲述RPC时,我们讲到了微服务架构的概念,也明白了软件架构从SOA 架构、RPC框架、分布式服务框架到目前的微服务架构的持续演化之路。既然微服务架构是从 之前这些架构演变而来的,那么它也具有以下共性。
首先,微服务架构是一个分布式的系统架构。也就是说分布式系统设计的原则、经验,以及常用的分布式基础设施和中间件依然是微服务架构中的重要组成部分,如果拋开分布式架构中的这些技术,只是空谈微服务架构,则好像空中楼阁。
其次,与 SOA架构一样,微服务架构与开发语言无关,它并没有公认的技术标准规范与实施方案指南,它更多地体现了一种被普遍接受的新的设计理念和指导思想,归纳下来有以下几点。
最后,微服务架构也有某些事实上公认的框架与工具, 目前最经典的有以下三个微服务架构开源平台。
上述这三个经典微服务架构平台各自能提供完备的微服务架构框架与管理工具,在技术上各有千秋,从总体上来看Google出品的Kubemetes平台是当之无愧的微服务架构之王。
接下来,我们一起看看在实施一个微服务架构项目的过程中可能遇到的问题及应对策略。
首先,架构师需要对项目组的全体成员进行培训,让大家明白微服务架构的思想和优点,培训的一个重要目标是要让大家明白,微服务架构在实施过程中会给项目组带来很明显的技能升级需求,不管是对于开发人员还是对于运维测试人员来说,这都是一个难得的新技术学习与 自我技能提升的好机会,希望大家顶住压力完成项目。
其次,要正确选择一个合适的微服务架构平台而不是自己研发。这种大型基础平台的研发成本很高、开发周期长而且平台可持续升级的可能性较低,因此目前很少有公司会自己进行研发,即使是RedHat这样有实力、有经验的开源软件服务型公司,也放弃了自己的微服务架构转而应用Google的 Kubemetes 那么,如何选择适合自己公司和项目组的微服务架构平台呢?以上文提到的三个典型的微服务架构平台为例,可参考如下条件进行选择。
再者,微服务架构的项目在实施过程中经常需要考虑如下工作。
接下来,我们来看看如何设计系统中的微服务。一开始,我们其实并不很清楚哪些功能和服务要设计成一个微服务,以及一个微服务宄竟应该包括多少个接口?每个接口应该如何设计? 笔者的建议是先粗粒度地划分微服务,每个微服务包括比较多的接口以减少微服务的个数,这样可以减少开发、程序打包、测试及部署的工作量,有利于快速推进项目。
系统中的微服务按照调用客户端的不同,可以划分为流程控制类、接口类及基础核心类三种,如下图所示。
一般来讲,这三种不同的微服务的接口设计也有所不同。
流程控制类微服务主要面向U I调用,所以它的接口设计应该以页面展示的便利性为第一目标,即大部分情况下采用JSON或 TEXT文本的方式传递参数与返回值,并且考虑在调用逻辑 出错的情况下,要告诉客户端错误的代码与原因,于是这类微服务的返回值通常会是下面的结构体:
public class CallResult
int resultCode; //返回代码,0 为成功,其他为调用错误
String resultData;//调用结果,通常为JSON的字符串
String errmsg;//调用错误的时候,展示给用户的可读错误信息
接口类微服务主要面向第三方系统,所以特别需要注意安全问题,因此接口设计中必须有安全措施,比较常见的方案是在调用参数中增加Token,并考虑参数加密的问题,同时建议接口类微服务在实现过程中重视日志的输出问题,以方便接口联调,以及方便在运行期间排查接口故障,日志中应该记录入口参数、关键逻辑分支、返回结果等重要信息。
基础核心类微服务主要被UI及其他两种微服务所调用,在这类微服务的接口设计中主要考虑效率和调用的方便性。建议设计得与普通Java类的接口看起来一样,这样可以避免将很多复杂 Bean对象作为参数及返回值时不但增加调用者的负担而且降低接口性能。
在微服务设计中,我们还需要考虑接口兼容性的问题,举例说明,对于如下微服务接口设计:
public void doBusiness(paraml,paramS,param3);
如果参数的个数存在增加的可能性,那么为了兼容旧版本,最好改为如下设计:
public class XXXBean {
private String paraml;
private String param2;
private String param3;
private String param4;
}
public void doBusiness(XXXBean thebean);
这样一来,旧接口无须重新编译,只要升级XXXBean所在的Jar包即可兼容旧版本。