第12章 Spring Boot与微服务
随着RESTful web服务和JSON数据交换格式流行,简单快速建立一个可连接的服务已经越来越方便了。随着持续交付概念推广以及Docker容器普及,微服务将这两种理念和技术结合起来,形成新的微服务+API + 平台的开发模式,以及容器化微服务的持续交付概念。
微服务(micro services)这个概念不是新概念,很多公司已经在实践了,例如亚马逊、Google、FaceBook,Alibaba。微服务架构模式(Microservices Architecture Pattern)的目的是将大型的、复杂的、长期运行的应用程序构建为一组相互配合的服务,每个服务可以独立迭代开发运维。
Micro这个词意味着每个服务都应该足够小,但是,这里的小不能用代码量来比较,而应该是从业务逻辑上比较——符合“单一职责模式”(SRP)原则的才叫微服务。
分布式的、去中心化的。Smart endpoints and dumb pipes, 本质就是去ESB,把所有的“思考”逻辑包括路由、消息解析等放在服务内部(Smart endpoints),去掉一个大一统的ESB,服务间轻(dumb pipes)通信,是比SOA更彻底的拆分。
要搞微服务架构,先要搞定RPC框架。
12.1 微服务架构
先来看看传统的web开发方式,通过对比比较容易理解什么是Microservice Architecture。和Microservice相对应的,这种方式一般被称为Monolithic(比较难传神的翻译)。所有的功能打包在一个 WAR包里,基本没有外部依赖(除了容器),部署在一个JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有逻辑。
Monolithic比较适合小项目,优点是:
开发简单直接,集中式管理
基本不会重复开发
功能都在本地,没有分布式的管理开销和调用开销
它的缺点也非常明显,特别对于互联网公司来说:
开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
代码维护难:代码功能耦合在一起,新人不知道何从下手
部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
扩展性不够:无法满足高并发情况下的业务需求
于是诞生了基于微服务的架构。简单来说, 微服务的目的是有效的拆分应用,实现敏捷开发和部署 。
SOA简述
早在1996年,Gartner就提出面向服务架构(SOA)。SOA阐述了“对于复杂的企业IT系统,应按照不同的、可重用的粒度划分,将功能相关的一组功能提供者组织在一起为消费者提供服务”,其目的是为了解决企业内部不同IT资源之间无法互联而导致的信息孤岛问题。
2002年,SOA被称作"现代应用开发领域最重要的课题之一",其正在帮助企业从资源利用的角度出发,将IT资源整合成可操作的、基于标准的服务,使其能被重新组合和应用。
但是,由于SOA本身的广义性以及抽象性,在其诞生的相当长一段时间内,人们对SOA存在着不同的认知和理解。
到2000年左右,ESB(Enterprise Service Bus)、WebService、SOAP等这类技术的出现,才使得SOA渐渐落地。同时,更多的厂商像IBM、Oracle等也分别提出基于SOA的解决方案或者产品。
实际上,微服务架构并不是一个全新的概念。仔细分析SOA的概念,就会发现,其和我们今天所谈到的微服务思想几乎一致。那在SOA诞生这么多年后,为什么又提出了微服务架构呢?
鉴于过去十几年互联网行业的高速发展,以及敏捷、持续集成、持续交付、DevOps,云技术等的深入人心,服务架构的开发、测试、部署以及监控等,相比我们提到的传统的SOA实现,已经大相径庭,主要区别如下表所示:
SOA实现 | 微服务架构实现 |
---|---|
企业级,自顶向下开展实施 | 团队级,自底向上开展实施 |
服务由多个子系统组成,粒度大 | 一个系统被拆分成多个服务,粒度细 |
企业服务总线,集中式的服务架构 | 无集中式总线,松散的服务架构 |
集成方式复杂(ESB/WS/SOAP) | 集成方式简单(HTTP/REST/JSON) |
单块架构系统,相互依赖,部署复杂 | 服务都能独立部署 |
相比传统SOA的服务实现方式,微服务更具有灵活性、可实施性以及可扩展性,其强调的是一种独立测试、独立部署、独立运行的软件架构模式。
微服务是什么?
在CPU处理器的指令集中,有CISC与RISC。
在操作系统中,有宏内核与微内核。
微服务,本质是一个系统架构解耦的过程。它是把一个大型复杂系统服务M(Monolithic Architecture,整体式架构)拆分成多个相对简单独立的子系统的服务MS(Microservice Architecture, 微服务架构)ms1, ms2, ms3, ... 。
系统中的各个微服务可被独立部署,各个微服务之间松耦合。之前整体的系统服务M,在MS中通过微服务提供的API交互完成。API之间的通信由RPC框架来完成。
这个思想理念,跟UNIX哲学理念——
小是美的。(Small is Beautiful)
是相通的。
另外,不同的微服务MS可以使用不同的技术架构,比如Node.js ,Java, Ruby, Python等等,这些单个的服务都可以独立完成交付生命周期。
我们最早使用传统的整体式架构应用开发系统,如CRM、ERP等大型应用,可能会遇到以下的一些问题:
1.随着新需求的不断增加,更新和迭代大型的整体式应用会变得越来越困难;
2.随着移动互联网的快速发展,要求我们能够实现功能的快速迭代上线;
3.但对于快速变化的需求,受到整体式应用架构的限制,有时候显得力不从心;
此外,大量开源轻量级技术不断涌现并日渐成熟:
轻量级运行时技术的出现(node.js, WAS Liberty等);
新的思想方法论与工具(Agile, DevOps, TDD, CI, XP, Puppet, Chef…);
新的轻量级协议(RESTful API接口, 轻量级消息机制);
简化的基础设施:操作系统虚拟化, 容器化(e.g. Docker), 基础设施即服务 (IaaS), 工作负载虚拟化(Kubernetes,Spark…)等;
服务平台化(PaaS): 云服务平台上具有自动缩放、工作负载管理、SLA 管理、消息机制、缓存、构建管理等各种按需使用的服务;
新的可替代数据持久化模型:如NoSQL, MapReduce, BASE, CQRS等;
标准化代码管理,如:Gitlab等。
这一切都催生了新的架构设计风格 – 微服务架构的出现。
在整体式架构应用中,我们将所有功能都打成一个包,可以是JAR、WAR、EAR或其它归档格式,然后,直接运行它,或者丢到一个容器(例如Tomcat)里跑。
整体式架构应用的一些不足:
不够灵活:对应用程序做任何细微的修改都需要将整个应用程序重新构建、重新部署。开发人员需要等到整个应用程序部署完成后才能看到变化。如果多个开发人员共同开发一个应用程序,那么还要等待其他开发人员完成了各自的开发。这降低了团队的灵活性和功能交付频率;
妨碍持续交付:单体应用可能会比较大,构建和部署时间也相应地比较长,不利于频繁部署,阻碍持续交付。在移动应用开发中,这个问题会显得尤为严重;
受技术栈限制:对于这类应用,技术是在开发之前经过慎重评估后选定的,每个团队成员都必须使用相同的开发语言、持久化存储及消息系统,而且要使用类似的工具,无法根据具体的场景做出其它选择;
技术债务:“不坏不修(Not broken,don’t fix)”,这在软件开发中非常常见,单体应用尤其如此。系统设计或写好的代码难以修改,因为应用程序的其它部分可能会以意料之外的方式使用它。随着时间推移、人员更迭,这必然会增加应用程序的技术债务。
而随着业务需求的快速发展变化,敏捷性、灵活性和可扩展性需求不断增长,迫切需要一种更加快速高效的软件交付方式。于是,微服务架构应运而生。
(当然,如果你没有遇到诸如上面的问题,你可能也就用不到微服务的架构了。)
这里的“微”不是针对代码行数而言,而是说服务的范围限定到单个功能。
微服务特点
康威定律:任何设计系统的组织,最终产生的设计等同于组织之内、之间的沟通结构。系统架构的设计符合组织沟通结构取得的收益最大。
微服务有如下特点:
小, 且专注于做⼀件事情
进程独立
轻量级的通信机制
松耦合
独立部署
领域驱动设计:应用程序功能分解可以通过Eric Evans在《领域驱动设计》中明确定义的规则实现;每个团队负责与一个领域或业务功能相关的全部开发;团队拥有全系列的开发人员,具备用户界面、业务逻辑和持久化存储等方面的开发技能;
单一职责原则:每个服务应该负责该功能的一个单独的部分,这是SOLID原则之一;
明确发布接口:每个服务都会发布一个定义明确的接口,而且保持不变;服务消费者只关心接口,而对于被消费的服务没有任何运行依赖;
独立部署、升级、扩展和替换:每个服务都可以单独部署及重新部署而不影响整个系统。这使得服务很容易升级,每个服务都可以沿着《Art of Scalability》一书定义的X轴和Z轴进行扩展;
可以异构/采用多种语言:每个服务的实现细节都与其它服务无关,这使得服务之间能够解耦,团队可以针对每个服务选择最合适的开发语言、持久化存储、工具和方法;
轻量级通信:服务通信使用轻量级的通信协议,例如,同步的REST,异步的AMQP、STOMP、MQTT等。
微服务架构的思想本质跟互联网的思想是一致的。它的组件对外发布的服务视同HTTP协议,采用HTTP Rest API的方式来进行。很多开放平台的API服务,基本都采用了Http API的方式进行服务的发布和管理。
Fictitious e-commerce application
Let’s imagine that you are building an e-commerce application that takes orders from customers, verifies inventory and available credit, and ships them. The application consists of several components including the StoreFrontUI, which implements the user interface, along with some backend services for checking credit, maintaining inventory and shipping orders. The application consists of a set of services.
基于微服务的架构, 目的是有效的拆分应用,实现敏捷开发和部署 。
服务之间如何通信?
因为所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通行就是IPC(inter process communication),最通用的有两种方式:
同步调用
REST(JAX-RS,Spring Boot)
RPC(Thrift, Dubbo)
异步消息调用
Kafka, Notify, MetaQ
微服务优点
相应地,微服务具有如下优点:
迭代开发灵活,快速适应需求变化(前提是,得架构良好才行);
局部修改很容易部署,有利于持续集成和持续交付;
故障隔离,一个服务出现问题不会影响整个应用;
技术栈自由。
随着持续交付概念推广以及Docker容器普及,微服务将这两种理念和技术结合起来,形成新的微服务+API + 平台的开发模式,提出了容器化微服务的持续交付概念。
传统Monolithic的DevOps开发队伍方式,如下图:
这种整体型架构要求产品队伍横跨产品管理 Dev开发 QA DBA 以及系统运营管理,而微服务架构引入以后,如下图:
微服务促进了DevOps方式的重组,将一个大臃肿的整体产品开发队伍切分为根据不同微服务的划分的产品队伍,以及一个大的整体的平台队伍负责运营管理,两者之间通过API交互,做到了松耦合隔绝。
由于Docker引入,不同的微服务可以使用不同的技术架构,比如Node.js Java Ruby Python等等,这些单个的服务都可以独立完成交付生命周期,如下:
微服务缺点
微服务看上去像一枚银弹,可以解决许多软件开发方面的问题。这看上去很美好,但并不易于实现。微服务会极大地增加运维工作量,使用微服务,一些技术债务势必从开发转到运维,因此,你最好有一个一流的开发运维团队。
总体来看,微服务架构可能带来过多的操作。缺点如下:
分布式系统可能复杂难以管理。
分布式部署跟踪解决问题难。
当服务数量增加,管理复杂性增加。
系统部署依赖(DevOps)
服务间通信成本(RPC框架)
数据一致性
系统集成测试
系统监控等。
当然,这是一个循序渐进的重构的过程。
因此,微服务对基础设施提出了一些额外的需求。通常,我们将它们总称为NoOps,本质上讲,就是一组服务,提供一个更好的应用程序部署流程并确保其运行,包括服务复制、服务发现、服务恢复和服务监控等。
服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图:
服务A是欧洲团队提供服务,欧洲团队的技术背景是Java,可以用Java实现服务;
服务B是美洲团队提供服务,可以用C++实现服务;
服务C是中国团队提供服务,可以用Go实现服务;
服务的上游调用方,按照接口、协议即可完成对远端服务的调用。
但实际上,99.9%的公司的团队规模有限,技术团队人数也有限,基本是使用同一套技术体系来调用和提供服务的:
这样的话,如果没有统一的服务框架,RPC框架,各个团队的服务提供方就需要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理、状态机等“业务之外”的重复技术劳动,造成整体的低效。所以,统一RPC框架把上述“业务之外”的技术劳动统一处理,是服务化首要解决的问题。
六种微服务架构
简单介绍六种微服务架构模式[7]。
聚合器微服务设计模式
这是一种最常用也最简单的设计模式,如下图所示:
微服务架构的设计模式
聚合器调用多个服务实现应用程序所需的功能。它可以是一个简单的Web页面,将检索到的数据进行处理展示。它也可以是一个更高层次的组合微服务, 对检索到的数据增加业务逻辑后进一步发布成一个新的微服务,这符合DRY原则。另外,每个服务都有自己的缓存和数据库。如果聚合器是一个组合服务,那么它 也有自己的缓存和数据库。聚合器可以沿X轴和Z轴独立扩展。
代理微服务设计模式
这是聚合器模式的一个变种,如下图所示:
微服务架构的设计模式
在这种情况下,客户端并不聚合数据,但会根据业务需求的差别调用不同的微服务。代理可以仅仅委派请求,也可以进行数据转换工作。
链式微服务设计模式
这种模式在接收到请求后会产生一个经过合并的响应,如下图所示:
微服务架构的设计模式
在这种情况下,服务A接收到请求后会与服务B进行通信,类似地,服务B会同服务C进行通信。所有服务都使用同步消息传递。在整个链式调用完成之前,客户端会一直阻塞。因此,服务调用链不宜过长,以免客户端长时间等待。
分支微服务设计模式
这种模式是聚合器模式的扩展,允许同时调用两个微服务链,如下图所示:
微服务架构的设计模式
数据共享微服务设计模式
自治是微服务的设计原则之一,就是说微服务是全栈式服务。但在重构现有的“单体应用(monolithic application)”时,SQL数据库反规范化可能会导致数据重复和不一致。因此,在单体应用到微服务架构的过渡阶段,可以使用这种设计模式,如下图所示:
微服务架构的设计模式
在这种情况下,部分微服务可能会共享缓存和数据库存储。不过,这只有在两个服务之间存在强耦合关系时才可以。对于基于微服务的新建应用程序而言,这是一种反模式。
异步消息传递微服务设计模式
虽然REST设计模式非常流行,但它是同步的,会造成阻塞。因此部分基于微服务的架构可能会选择使用消息队列代替REST请求/响应,如下图所示:
微服务架构的设计模式
12.2 Spring Cloud构建微服务架构
作者:一个会写诗的程序员
链接:https://www.jianshu.com/p/572f264d0bb5