1.1 微服务架构的出现
从单体应用架构发展到SOA架构,再到微服务架构,应用架构经历了多年的不断演进。微服务架构不是凭空产生的,而是技术发展的必然结果,分布式云平台的应用环境使得微服务代替单体应用成为互联网大型系统的架构选择。目前,虽然微服务架构还没有公认的技术标准和规范草案,但业界已经有了一些很有影响力的开源微服务架构解决方案,在进行微服务化开发或改造时可以进行相应的参考。
1.1.1 单体应用架构
与微服务架构对比的是传统的单体应用。Web应用程序发展的早期,大部分Web工程是将所有的功能模块打包到一起部署和运行,例如Java应用程序打包为一个war包,其他语言(Ruby、Python或者C++)编写的应用程序也有类似的做法。单体应用的实现架构类似于图1-1中的电影售票系统。
图1-1 电影售票系统的架构图
这个电影售票系统采用分层架构,按照调用顺序,从上到下为表示层、业务层、数据访问(DAO)层、DB层。表示层负责用户体验;业务层负责业务逻辑,包括电影、订单和用户三个模块;数据访问层负责DB层的数据存取,实现增删改查的功能。业务层定义了应用的业务逻辑,是整个应用的核心。在单体应用中,所有这些模块都集成在一起,这样的系统架构就叫做单体应用架构,或称为巨石型应用架构。单体应用是最早的应用形态,开发和部署都很简单。在中小型项目中使用单体应用架构,能体现出其优势,且单体应用的整体性能主要依赖于硬件资源和逻辑代码实现,应用架构自身不需要特别关注。
单体应用的集成非常简洁,IDE集成开发环境(如Eclipse)和其他工具都擅长开发一个简单应用;单体应用易于调试,由于一个应用包含所有功能,所以只需要简单运行此应用即可进行开发测试;单体应用易于部署,只需要把应用打包,拷贝到服务器端即可;通过负载均衡器,运行多个服务实例,单体应用可以轻松实现应用扩展。
但是,随着应用项目变得复杂、开发团队不断扩张之后,单体应用的不足和弊端将会变得很明显,主要有如下不足:
□ 可靠性:每个bug都可能会影响到整个应用的可靠性。因为所有模块都运行在一个进程中,任何一个模块中的一个bug,比如内存泄露,都可能拖垮整个进程。
□ 复杂性高:单体应用巨大的代码库可能会令人望而生畏,特别是对团队新成员来说。应用难以理解和迭代,进而导致开发速度减慢。由于没有清晰的模块边界,模块化会逐渐消失。
□ 持续部署困难:巨大的单体应用本身就是频繁部署的一大障碍。为了更新一个组件,必须重新部署整个应用。这会中断那些可能与更改无关的后台任务(例如Java应用中的Quartz任务),同时可能引发其他问题。另外,未被更新的组件有可能无法正常启动。重新部署会增加风险,进而阻碍频繁更新。
□ 扩展能力受限:单体架构只能进行一维扩展。一方面,它可以通过运行多个应用服务实例来增加业务容量,实现扩展。但另一方面,不同的应用组件有不同的资源需求:有的是CPU密集型的,有的是内存密集型的。单体架构无法单独扩展每个组件。
□ 阻碍技术创新:单体应用往往使用统一的技术平台或方案解决所有问题,团队的每个成员都必须使用相同的开发语言和架构,想要引入新的框架或技术平台非常困难。单体架构迫使团队长期使用在开发初期选定的技术栈,比如选择了JVM的语言,此时以非JVM语言编写的组件就无法在该单体架构的应用中使用。
1.1.2 SOA架构
面向服务的架构(SOA)是Gartner于20世纪90年代中期提出的。2002年12月,Gartner提出“面向服务的架构”是现代应用开发领域最重要的课题之一。
SOA的核心主体是服务,其目标是通过服务的流程化来实现业务的灵活性。服务就像一堆“元器件”,这些元器件通过封装形成标准服务,它们有相同的接口和语义表达规则。但服务要组装成一个流程和应用,还需要有效的“管理”,包括如何注册服务、如何发现服务、如何包装服务的安全性和可靠性,这些就是SOA治理。SOA治理是将SOA的一堆元器件进行有效组装。这是形成一个“产品”的关键,否则那些永远是一堆元器件,而无法形成一个有机整体。
完整的SOA架构由五大部分组成:基础设施服务、企业服务总线、关键服务组件、开发工具、管理工具等。
□ 基础设施:为整个SOA组件和框架提供一个可靠的运行环境,以及服务组件容器,它的核心组件是应用服务器等基础软件支撑设施,提供运行期完整、可靠的软件支撑。
□ 企业服务总线:提供可靠消息传输、服务接入、协议转换、数据格式转换、基于内容的路由等功能,屏蔽了服务的物理位置、协议和数据格式。
□ 关键服务组件:SOA在各种业务服务组件的分类。
□ 开发工具和管理工具:提供完善的、可视化的服务开发和流程编排工具,包括服务的设计、开发、配置、部署、监控、重构等完整的SOA项目开发生命周期。
具体来说,就是在分布式的环境中,将各种功能都以服务的形式提供给最终用户或者其他服务。企业级应用的开发多采用面向服务的体系架构来满足灵活多变、可重用性的需求。它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口采用中立的方式进行定义,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种各样的系统中的服务可以以一种统一和通用的方式进行交互。
SOA是在企业计算领域中提出的,目的是要将紧耦合的系统,划分为面向业务的、粗粒度、松耦合、无状态的服务。服务发布出来供其他服务调用,一组互相依赖的服务就构成了SOA架构的系统。基于这些基础的服务,可以将业务过程用类似BPEL(业务流程执行语言)流程的方式编排起来,BPEL反映的是业务处理的过程,这些过程对于业务人员更为直观。企业还需要一些服务治理的工具,比如服务注册库、监控管理等。在企业计算领域,如果不是交易系统的话,并发量都不是很大,所以大多数情况下,一台服务器就可以容纳许多的服务,这些服务采用统一的基础设施,可能都运行在一个应用服务器的进程中。虽然说是SOA架构,但还可能是单一的系统。
1.1.3 微服务架构
微服务最早是由Martin Fowler与James Lewis于2014年共同提出,需要了解细节的读者可以阅览https://martinfowler.com/articles/microservices.html。其实Martin先生并没有给出明确的微服务定义,根据其描述,微服务的定义可以概括如下:微服务架构是一种使用一系列粒度较小的服务来开发单个应用的方式;每个服务运行在自己的进程中;服务间采用轻量级的方式进行通信(通常是HTTP API);这些服务是基于业务逻辑和范围,通过自动化部署的机制来独立部署的,并且服务的集中管理应该是最低限度的,即每个服务可以采用不同的编程语言编写,使用不同的数据存储技术。
如今,微服务架构已经不是一个新概念了,很多业界前沿互联网公司的实践表明,微服务是一种渐进式的演进架构,是企业应对业务复杂性,支持大规模持续创新行之有效的架构手段。
1.组成
微服务架构是一种比较复杂、内涵丰富的架构模式,它包含很多支撑“微”服务的具体组件和概念,其中一些常用的组件及其概念如下:
□ 服务注册与发现:服务提供方将己方调用地址注册到服务注册中心,让服务调用方能够方便地找到自己;服务调用方从服务注册中心找到自己需要调用的服务的地址。
□ 负载均衡:服务提供方一般以多实例的形式提供服务,负载均衡功能能够让服务调用方连接到合适的服务节点。并且,服务节点选择的过程对服务调用方来说是透明的。
□ 服务网关:服务网关是服务调用的唯一入口,可以在这个组件中实现用户鉴权、动态路由、灰度发布、A/B测试、负载限流等功能。
□ 配置中心:将本地化的配置信息(Properties、XML、YAML等形式)注册到配置中心,实现程序包在开发、测试、生产环境中的无差别性,方便程序包的迁移。
□ 集成框架:微服务组件都以职责单一的程序包对外提供服务,集成框架以配置的形式将所有微服务组件(特别是管理端组件)集成到统一的界面框架下,让用户能够在统一的界面中使用系统。
□ 调用链监控:记录完成一次请求的先后衔接和调用关系,并将这种串行或并行的调用关系展示出来。在系统出错时,可以方便地找到出错点。
□ 支撑平台:系统微服务化后,各个业务模块经过拆分变得更加细化,系统的部署、运维、监控等都比单体应用架构更加复杂,这就需要将大部分的工作自动化。现在,Docker等工具可以给微服务架构的部署带来较多的便利,例如持续集成、蓝绿发布、健康检查、性能健康等等。如果没有合适的支撑平台或工具,微服务架构就无法发挥它最大的功效。
2.优点
微服务架构模式有很多优势可以有效解决单体应用扩大之后出现的大部分问题。首先,通过将巨大单体式应用分解为多个服务的方法解决了复杂性问题。在功能不变的情况下,应用分解为多个可管理的模块或服务。每个服务都有一个用RPC或者消息驱动API定义清楚的边界。微服务架构模式为采用单体式编码方式很难实现的功能提供了模块化的解决方案。由此,单个服务变得很容易开发、理解和维护。
其次,微服务架构模式使得团队并行开发得以推进,每个服务都可以由专门开发团队来开发。不同团队的开发者可以自由选择开发技术,提供API服务。这种自由意味着开发者不需要被迫使用之前采用的过时技术,他们可以选择最新的技术。甚至于,因为服务都是相对简单的,即使用新技术重写以前的代码也不是很困难的事情。
再次,微服务架构模式中每个微服务独立都是部署的。理想情况下,开发者不需要协调其他服务部署对本服务的影响。这种改变可以加快部署速度。UI团队可以采用AB测试,快速地部署变化。微服务架构模式使得持续化部署成为可能。
最后,微服务架构模式使得每个服务易于独立扩展。
3.挑战
微服务的一些想法是好的,但在实践中也会呈现出其复杂性,具体如下:
□ 运维要求较高。更多的服务意味着需要更多的运维投入。在单体架构中只需要保证一个应用的正常运行即可;而在微服务中,需要保证几十甚至几百个服务的正常运行与协作,这带来了巨大的挑战。
□ 分布式固有的复杂性。使用微服务构建的是分布式系统。对于一个分布式系统来说,系统容错、网络延迟、分布式事务等都会带来巨大的挑战。
□ 接口调整成本高。微服务之间通过接口进行通信。如果修改某个微服务的API,可能所有使用了该接口的微服务都需要做调整。
□ 重复劳动。很多服务可能都会使用到相同的功能,而这个功能并没有达到分解为一个微服务的程度,这个时候,可能各个服务都会开发这一功能,导致代码重复。
□ 可测试性的挑战。在动态环境下,服务间的交互会产生非常微妙的行为,难以进行可视化及全面测试。