前言
本书适合有一定Java基础且有志成为架构师的开发人员阅读。一个优秀的架构师必须要有扎实的编程功底和丰富的理论知识,不光要能完成架构设计,更要有能力将设计转换为实际的产品。不会写代码、纸上谈兵的“架构师”设计出来的“架构”是靠不住的。因此,本书将从相关的基础知识讲起,通过剖析一个小巧精练的微服务框架的核心,介绍这些基础知识是如何在实践中被灵活、适当地运用的。
本书不是关于微服务的理论书籍,也不是某个微服务框架的使用手册。微服务涉及的范围很广,我们很难在一本书里讲清楚微服务的方方面面。
目前相关的主流框架是Spring Cloud和Dubbo。虽然Spring Cloud和Dubbo都很强大,但这个世界上从来没有□好,只有更好,因此我们永远不要停下自己创新的脚步。我们依然可以有自己的想法,并勇于尝试、付诸实践。事实上Spring Cloud和Dubbo都存在各自的问题和不足。我们通过对它们的学习和研究,站在巨人的肩膀上,吸取它们的优点再加以创新,是完全有可能做到青出于蓝而胜于蓝的。
在正式开始之前,让我们先了解一下微服务的发展背景。
面向服务的架构
1996年,Gartner公司首次提出了面向服务的架构(Service-Oriented Architecture,SOA)这一软件设计思想。其核心理念是将一个个的业务功能包装成一个个的标准服务,为这些服务定义良好的接口和服务契约,以便在需要的时候可以重用和水平伸缩。通过将这些服务进行组合和编排,可以创建新的业务流程,或者灵活地修改现有流程,以适应不断变化的业务需求,让我们的系统功能更丰富、结构更灵活、更易于扩展。同时,让系统规模能够根据需要弹性伸缩,□大限度地利用现有资产,提高效率,降低成本。总之,要使我们的系统能更灵活、更快地响应不断变化的需求。
不过,受到当时计算机水平的限制,面向服务的架构思想在诞生之初,并没有得到广泛的关注和发展。随着软件系统的规模越来越大、越来越复杂,软件系统的架构也在不断地演进,面向服务的架构开始受到人们的关注和认可。目前,大型软件系统的服务端架构多数都是面向服务的架构,或者正在朝这一架构迁移。
要明确的是,面向服务的架构中的“服务”虽然也包括系统对外提供的服务,但更多的是指系统内部的各个“模块”或“组件”的“服务化”,以及模块(服务)之间的相互调用与协同。它是“分布式”与“服务化”两个技术发展趋势合流的产物。
分布式系统
所谓的“分布式”是相对于“集中式”的一种应用系统内部组织结构。相对于传统的集中式系统(单机应用系统和集群式应用系统都属于集中式系统),分布式系统将原本集中在一个服务端应用中的功能模块拆分出来,分为多个系统组件或应用,分散部署在多个服务器上,并通过网络将它们连接起来协同工作。而客户端系统感觉不到服务端系统内部的这种变化,仍然和原来调用集中式系统一样。
分布式设计使得原本集中在单个服务器上进行的计算或存储需求被分散到了多个服务器上,从而降低了我们对单一服务器的性能要求。这样就让我们能用相对廉价的PC服务器代替昂贵的传统服务器,并通过水平扩容的方式继续提升系统的处理能力。
分布式系统并没有约定其内部的各个组件或应用之间应采用什么样的形式来实现彼此通信。早期人们使用DCOM、CORBA等技术实现组件的暴露和远程访问。这便是分布式系统的早期形态。但是这些技术比较复杂且十分笨重,只在大型系统和企业级应用中被使用。尽管之后又出现了COM+、RMI、EJB等技术,但仍然比较笨重和难用。
服务化
早期的系统都是相互独立的。受限于计算机的处理能力,其规模都比较小。比如,财务系统和人力资源管理系统分别是两个不同的系统。它们可能由不同的软件厂商,采用不同的开发语言和技术开发,并运行在各式各样的操作系统和硬件设备上。随着企业发展的需要,人们试着在两个系统间建立通信,尝试让它们彼此协同。双方的通信方式和协议由厂商之间彼此协商来制定,开发起来成本很高。各个厂商都试图制定自己的通信技术标准和协议,并力争成为业内标准。显然,如果所有厂商都遵循同一套技术标准和通信协议,就能大大地降低开发成本,让各个系统彼此更容易地互联互通。
随着基于Web的应用的普及,以及XML技术的出现和成熟,出现了基于HTTP、XML的服务暴露与远程访问方式,这就是Web Services。但Web Services的协议和实现方式很多,技术标准也多种多样。企业内部各系统之间的互联互通仍然比较麻烦。于是,企业服务总线(Enterprise Service Bus,ESB)系统被设计来实现各系统之间的服务接口适配和管理,以便各系统能够用自己熟悉的技术、标准和规范来相互调用彼此的服务。随着时间的推移,简单对象访问协议(Simple Object Access Protocol,SOAP)、Web服务描述语言(Web Services Description Language,WSDL),以及通用描述、发现与集成服务(Universal Description,Discovery and Integration,UDDI)协议逐渐成为主流的Web Services标准和规范。
后来,随着互联网技术的发展,基于HTTP RESTful的轻量级Web Services逐渐取代了基于SOAP的传统Web Services技术成为主流。由于HTTP RESTful服务暴露和调用开销比SOAP小很多,且速度更快,这就使得我们可在大型系统内部也大量使用,以作为各子系统之间,尤其是异构子系统之间□佳的通信形式。
面向服务
当我们将系统中的模块或组件服务化,代替COM+、RMI、EJB等分布式领域的组件通信技术后,系统架构就转变为面向服务的架构。当然,分布式系统中的很多组件是难以服务化的。不是所有的模块和组件都适合服务化。比如,有些模块的调用频率很高,接口复杂,转变成服务后,访问性能可能无法满足设计要求。又比如,有些模块与模块之间的耦合度较高,如果不进行重构来解耦,那么是无法单独作为服务暴露的。还有些模块的重用度不高或调用频率过低,没有服务化的必要。在对系统进行SOA改造时,一定要分析清楚。
综上所述,面向服务的架构是分布式架构中的一种。面向服务的架构一定是分布式架构,但分布式架构不一定面向服务。能够对外提供服务的系统并不一定是面向服务的架构,面向服务架构的系统也不一定对外暴露服务。
什么是微服务
顾名思义,微服务就是指粒度较小的服务。这意味着我们要对现有的分布式系统进行进一步的拆分,将其划分为更多、更小的服务来进行设计或重构。“微服务”的概念源于2014年3月Martin Fowler所写的一篇文章Microservices。它扩大了面向服务架构中“服务”的概念。不再局限于系统与系统之间的接口调用,也不局限于某种具体的服务形式。系统中凡是可被复用的功能模块都可以被“服务化”,转变为“服务”。这些服务可以对外暴露,也可能仅限于在系统内部使用。这对面向服务架构提出了更高的设计要求。由于服务数量更多、粒度更小,因此管控难度会更大,对性能的要求也更高。
那么,我们为什么要将系统拆分成一个个的微服务呢?
微服务的好处
微服务有如下好处。
1. 方便编排和重用
当我们在开发新功能时,可能需要复用现有的模块。以往我们需要将可复用的代码放到jar包中,并在工程中引用。这容易导致依赖关系的复杂和混乱,而且每次都需要重新编译和打包,也很不方便,更不要说对现有的模块进行编排和组合了。将这些模块转变为服务后,我们只需要调用这些服务,而不需要关心服务的具体实现、依赖和提供者。同时还能够使用服务编排工具将现有服务编排到新的流程中,组合成为新的服务,或者修改现有的服务流程。
2. 方便开发和调试
每一个微服务专注于单一功能,并通过定义良好的接口来清晰表述它的边界。服务越小,复杂度越低,开发起来也就越简单、越快,调试和维护也更方便。这就缩短了服务开发和修改的周期,使程序能更快地迭代。
3. 方便部署与更新
微服务一般随应用部署。一个系统中有若干可独立运行的应用,每个应用通常提供了一个或多个微服务。当某个微服务发生变更时,只需编译和部署相应的应用,而不用重新编译和部署整个系统。这使得部署发布更加高效,同时也缩小了每次变更和部署的影响范围,降低了风险。
4. 系统集成更方便
使用不同语言、不同技术栈开发的服务,只要按照统一的协议暴露,比如统一使用HTTP RESTful形式暴露为服务,就可以方便地相互调用和协同。这使得我们能够将各类系统轻松集成在一起。
5. 提高容错能力
某一模块或组件发生故障时,容易导致整个系统变得不可用。比如,某个模块的内存泄漏可能导致整个应用因内存不足而崩溃。由于微服务架构中的服务粒度很小,且相互隔离,因此即使某个服务出现问题,处理起来也相对容易,影响范围有限。微服务系统可以通过失败重试、失败转移、服务降级等机制实现容错处理,避免问题扩大,微服务系统甚至能自动从故障中恢复(自愈)。
6. 方便横向扩展
当某个服务出现性能瓶颈时,我们只需要增加此服务所属应用的部署数量,而不用增加整个系统的部署。而且,由于不同的服务对资源的要求不同,我们可以根据实际情况灵活地对服务进行混合部署,以便更合理地分配服务器资源。
RPC与微服务
微服务环境下服务的粒度更细,调用频率也更高,一般用于系统内部的面向服务架构,而不是直接对外提供服务。在这种场景下,Web Services的跨语言、跨平台优势不再那么重要,Web Services的易用性问题和性能问题反而变得突出起来。
随着Socket、多线程、序列化等技术的发展,涌现出了很多优秀的RPC框架,以代替传统的RMI等技术。与Web Services偏向对外暴露服务与远程调用不同,RPC框架专注于细粒度(方法级别)的、系统内部模块或组件之间的相互调用与协同。由于多数RPC框架采用Socket长连接和二