带你读《极简Spring Cloud实战》之一:微服务与Spring Cloud-阿里云开发者社区

开发者社区> 华章出版社> 正文

带你读《极简Spring Cloud实战》之一:微服务与Spring Cloud

简介: 本书从实战、进阶、全面配置三个层次展开介绍,分为三篇。基础服务篇介绍构建一个核心微服务架构不可缺少的部分。任务与消息篇则着重介绍Spring Cloud 针对消息、任务、调用依赖等方面的支持方案。微服务实战篇基于Spring Cloud+Docker构建一个精简而又五脏俱全的小项目。

云计算与虚拟化技术丛书
点击查看第二章
点击查看第三章
极简Spring Cloud实战
image.png
胡劲寒 编著
第一篇

基础服务篇

本篇将为读者介绍微服务架构的演进过程,带领读者了解什么是微服务,为什么需要微服务,以及微服务与Spring Cloud之间是什么关系,为什么要选择Spring Cloud来实现微服务而不是市面上现存的其他解决方案。了解之后,相信读者会有自己的答案。

第1章

微服务与Spring Cloud

本章将带领读者从服务端架构的演进历程开篇,描述服务端架构演进至微服务的必然,同时介绍实现微服务的最佳方式—Spring Cloud,并对Spring Cloud的组成及其同业对比的优势进行初步介绍。读者通过本章能够了解微服务是什么,以及Spring Cloud如何帮助技术开发人员快速实现微服务。

1.1 架构演进

1.1.1 服务端架构发展

由于人们首先想到的是让两台或多台计算机相互通信,因此构思出了,如图1-1所示的简易通信模型。
image.png
互相通信的两个服务可以满足最终用户的一些需求。但这个示意图显然过于简单,缺少包括通过代码操作的字节转换和在线路上收发的电信号转换在内的多个层。虽然一定程度上的抽象对于讨论是必需的,但仍需添加网络协议栈(组件)以增加细节内容,如图1-2所示。
image.png
上述这个修改过的模型自20世纪50年代一直使用至今。一开始,计算机很稀少,也很昂贵,所以两个节点之间的每个环节都被精心制作和维护。随着计算机变得越来越便宜,连接的数量和数据量大幅增加。人们越来越依赖网络系统,工程师需要保证他们构建的软件能够达到用户所要求的服务质量。
当然,还有许多问题急需解决以达到用户要求的服务质量。人们需要找到解决方案让机器互相发现,通过同一条线路同时处理多个连接,允许机器在非直连的情况下互相通信,通过网络对数据包进行路由、流量加密等。
其中,有一种机制称为流量控制,下面以此为例。流量控制是一种防止一台服务器发送的数据包超过下游服务器可以承受上限的机制。这是必要的,因为在一个联网的系统中,至少有两台不同的、独立的计算机,彼此之间互不了解。计算机A以给定的速率向计算机B发送字节,但不能保证B可以连续地、以足够快的速度来处理接收到的字节。例如,B可能正在忙于并行运行其他任务,或者数据包可能无序到达,并且B可能被阻塞以等待本应该第一个到达的数据包。这意味着A不仅不知道B的预期性能,还可能让事情变得更糟,导致B过载,B现在必须对所有这些传入的数据包进行排队处理。
一段时间以来,大家寄希望于建立网络服务和应用程序的开发者能够通过编写代码来解决上面提出的挑战。在这个流程控制示例中,应用程序本身必须包含某种逻辑来确保服务不会因为数据包的原因而过载。这种重联网的逻辑与业务逻辑一样重要。抽象示意图如图1-3所示。
随着像TCP/IP这样的标准横空出世,流量控制和许多其他问题的解决方案被融入网络协议栈本身。这意味着这些流量控制代码仍然存在,但已经从应用程序转移到了操作系统提供的底层网络层,如图1-4所示。
这个模型相当成功。几乎任何一个组织都能够使用商业操作系统附带的TCP/IP协议栈来驱动他们的业务,即使有高性能和高可靠性的要求。
image.png
image.png

1.1.2 微服务架构

随着节点和稳定连接的数量越来越多,行业中出现了各种各样的网络系统:从细粒度的分布式代理和对象,到由较大但重分布式组件组成的面向服务的架构。这样的分布式系统带来了几个难题,有一些是新出现的,也有原有难题的“升级版”。
20世纪90年代,Peter Deutsch和他在Sun公司的同事撰写了《分布式计算的八大错误》一文,文中列出了人们在使用分布式系统时通常会做出的一些假设。Peter认为,这些假设在更原始的网络架构或理论模型中可能是真实存在的,但在现代世界中是不成立的:

  • 网络是可靠的;
  • 延迟为零;
  • 带宽是无限的;
  • 网络是安全的;
  • 拓扑是不变的;
  • 管理员实时监控维护;
  • 传输成本为零;
  • 网络是同构的。

因此,工程师们必须处理这些问题。
为了处理更复杂的问题,需要转向更加分散的系统(我们通常所说的微服务架构),这在可操作性方面提出了新的要求。下面则列出了必须要处理的问题:

  • 计算资源的快速提供;
  • 基本的监控;
  • 快速部署;
  • 易于扩展的存储;
  • 可轻松访问边缘;
  • 认证与授权;
  • 标准化的RPC;

因此,尽管数十年前开发的TCP/IP协议栈和通用网络模型仍然是计算机之间相互通信的有力工具,但更复杂的架构引入了其他层面的问题。此时业界出现了微服务思想,以期解决上述问题。例如,微服务用服务发现与断路器技术来解决上面列出的几个弹性扩展和分布式问题,如图1-5所示。

微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并且可通过全自动部署机制独立部署。这些服务共用一个最小型的集中式的管理,服务可用不同的语言开发,使用不同的数据存储技术。
我们为了将系统构建为微服务架构,除了服务是可独立部署、可独立扩展的之外,每个服务都提供一个固定的模块边界,甚至允许不同的服务用不同的语言开发,由不同的团队管理。图1-6展示了单体应用到微服务的简易图解。
image.png

然而历史往往会重演,第一批基于微服务构建的系统遵循了与前几代联网计算机类似的策略。这意味着落实上述需求的责任落在了编写服务的工程师身上。我们以服务发现和断路器来说明。
服务发现是在满足给定查询条件的情况下自动查找服务实例的过程,例如,一个名叫Teams的服务需要找到一个名为Players的服务实例,其中该实例的environment属性设置为production。当用户调用一些提供提供服务发现的组件,它们会返回一个满足条件的服务列表。对于中心化的架构而言,这是一个非常简单的任务,通常可以使用DNS、负载均衡器和一些端口号的约定(例如,所有服务将HTTP服务器绑定到8080端口)来实现。而在更分散的环境中,任务开始变得越来越复杂,对于以前可以通过盲目信任DNS来查找依赖关系的服务,现在必须处理诸如客户端负载均衡、多种不同环境、地理位置上分散的服务器等问题。如果之前只需要一行代码来解析主机名,那么现在的服务则需要很多行代码来处理由分布式引入的各种问题。
断路器是由Michael Nygard在其编写的《Release It》一书中引入的模式,书中对该模式的一些总结:
断路器背后的基本思路非常简单。将一个受保护的函数调用包含在用于监视故障的断路器对象中。一旦故障达到一定阈值,则断路器跳闸,并且对断路器的所有后续调用都将返回错误,并完全不接受对受保护函数的调用。通常,如果断路器发生跳闸,还需要对其进行某种监控警报。
随着分布式水平的提高,它们也会变得越来越复杂。系统发生错误的概率随着分布式水平的提高呈指数级增长,比如一个组件中的一个故障可能会在许多客户端和客户端的客户端上产生连锁反应,从而触发数千个电路同时跳闸。而且,以前可能只需几行代码就能处理某个问题,现在需要编写大量的代码才能处理。
因此微服务反对之声也很强烈,认为微服务增加了系统维护、部署的难度,导致一些功能模块或代码无法复用,增加系统集成与测试的难度,而且随着系统规模增长,会导致系统越来越复杂。那么有没有一种框架或开发平台可以尽可能便捷、一站式解决上述问题呢?有!那便是Spring Cloud。

1.2 Spring Cloud面面观

为了降低用户构建和维护分布式系统的难度,推动微服务的落地,Spring Cloud提供了快速构建分布式微服务系统的一些常用功能,如配置管理、服务发现、断路器、智能路由、服务代理、控制总线等提供的一套开发工具。这些工具就相当于分布式系统的样板,Spring Cloud的使用者可以使用这些样板工具快速构建服务以及相关应用。这些工具能够在任何分布式环境中良好运行,如开发者的计算机、数据中心以及类似Cloud Foundry这样的管理平台。
Spring Cloud适用于以下场景:配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等。
接下来从服务化架构演进的角度来讲述为什么Spring Cloud更适应微服务架构。

1.2.1 Spring Cloud与Dubbo对比

我们先从Nginx说起,了解为什么需要微服务。最初的服务化解决方案是给相同服务提供一个统一的域名,然后服务调用者向这个域发送HTTP请求,由Nginx负责请求的分发和跳转。
这种架构存在很多问题:Nginx作为中间层,在配置文件中耦合了服务调用的逻辑,这削弱了微服务的完整性,也使得Nginx在一定程度上变成了一个重量级的ESB。图1-7标识出了Nginx的转发信息流走向。
服务的信息分散在各个系统,无法统一管理和维护。每一次的服务调用都是一次尝试,服务消费方并不知道有哪些实例在给他们提供服务。这带来了一些问题:
image.png

  • 无法直观地看到服务提供方和服务消费方当前的运行状况与通信频率;
  • 消费方的失败重发、负载均衡等都没有统一策略,这加大了开发每个服务的难度,不利于快速演化。

为了解决上面的问题,我们需要一个现成的中心组件对服务进行整合,将每个服务的信息汇总,包括服务的组件名称、地址、数量等。服务的调用方在请求某项服务时首先通过中心组件获取提供服务的实例信息(IP、端口等),再通过默认或自定义的策略选择该服务的某一提供方直接进行访问,所以考虑引入Dubbo。
Dubbo是阿里开源的一个SOA服务治理解决方案,文档丰富,在国内的使用度非常高。图1-8为Dubbo的基本架构图,使用Dubbo构建的微服务已经可以较好地解决上面提到的问题。
image.png

从图1-8中,可以看出:

  • 调用中间层变成了可选组件,消费方可以直接访问服务提供方;
  • 服务信息被集中到Registry中,形成了服务治理的中心组件;
  • 通过Monitor监控系统,可以直观地展示服务调用的统计信息;
  • 服务消费者可以进行负载均衡、服务降级的选择。

但是对于微服务架构而言,Dubbo并不是十全十美的,也有一些缺陷。

  • Registry严重依赖第三方组件(ZooKeeper或者Redis),当这些组件出现问题时,服务调用很快就会中断。
  • Dubbo只支持RPC调用。这使得服务提供方与调用方在代码上产生了强依赖,服务提供方需要不断将包含公共代码的Jar包打包出来供消费方使用。一旦打包出现问题,就会导致服务调用出错。

笔者认为,Dubbo和Spring Cloud并不是完全的竞争关系,两者所解决的问题域并不一样:Dubbo的定位始终是一款RPC框架,而Spring Cloud的目标是微服务架构下的一站式解决方案。如果非要比较的话,Dubbo可以类比到Netflix OSS技术栈,而Spring Cloud集成了Netflix OSS作为分布式服务治理解决方案,但除此之外Spring Cloud还提供了配置、消息、安全、调用链跟踪等分布式问题解决方案。
当前由于RPC协议、注册中心元数据不匹配等问题,在面临微服务基础框架选型时Dubbo与Spring Cloud只能二选一,这也是大家总是拿Dubbo和Spring Cloud做对比的原因之一。Dubbo已经适配到Spring Cloud生态,比如作为Spring Cloud的二进制通信方案来发挥Dubbo的性能优势,Dubbo通过模块化以及对HTTP的支持适配到Spring Cloud。

1.2.2 Spring Cloud好在哪里

作为新一代的服务框架,Spring Cloud提出的口号是开发“面向云的应用程序”,它为微服务架构提供了更加全面的技术支持。结合我们一开始提到的微服务的诉求,参见表1-1,把Spring Cloud与Dubbo进行一番对比。
image.png
Spring Cloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方,不存在代码级别的强依赖,这在强调快速演化的微服务环境下显得更加合适。
很明显,Spring Cloud的功能比Dubbo更加强大,涵盖面更广,而且作为Spring的拳头项目,它也能够与Spring Framework、Spring Boot、Spring Data、Spring Batch等其他Spring项目完美融合,这些对于微服务而言是至关重要的。前面提到,微服务背后一个重要的理念就是持续集成、快速交付,而在服务内部使用一个统一的技术框架,显然比将分散的技术组合到一起更有效率。更重要的是,相比于Dubbo,它是一个正在持续维护的、社区更加火热的开源项目,这就可以保证使用它构建的系统持续地得到开源力量的支持。
下面列举Spring Cloud的几个优势。

  • Spring Cloud来源于Spring,质量、稳定性、持续性都可以得到保证。
  • Spirng Cloud天然支持Spring Boot,更加便于业务落地。
  • Spring Cloud发展得非常快,从开始接触时的相关组件版本为1.x,到现在将要发布2.x系列。
  • Spring Cloud是Java领域最适合做微服务的框架。
  • 相比于其他框架,Spring Cloud对微服务周边环境的支持力度最大。对于中小企业来讲,使用门槛较低。

1.2.3 Spring Cloud子项目与解决方案

我们从整体上来看一下Spring Cloud各个组件如何配套使用,如图1-9所示。
image.png
从图1-9可以看出,Spring Cloud各个组件相互配合,合作支持了一套完整的微服务架构。
Spring Cloud从设计之初就考虑了绝大多数互联网公司架构演化所需的功能,这些功能都是以插拔的形式提供,方便合理选择需要的组件进行集成,从而使用过程中更加平滑、顺利。
Spring Cloud提供了标准化的、一站式的技术方案。下面按照Spring Cloud子项目和其提供的分布式方案来分别了解Spring Cloud价值。
系统一旦走向分布式,其复杂程度成倍增长,传统单体应用那种只考虑业务逻辑的开发方式已经不再适用。正因其复杂性,目前只有业务需求大的大型互联网公司才会(被迫)采用,而且需要投入大量的技术力量来开发基础设施,也造成了小公司“用不起”分布式架构的情况。现在这一局面正在逐渐被打破,因为Netflix开源了经过实战考验的一系列基础设施构件,加上Spring Cloud的大力支持,开发分布式系统已经不再像以前那样可怕了。
(1)服务的注册发现和软负载均衡
Spring Cloud Netflix通过Eureka Server实现服务注册中心,通过Ribbon实现软负载均衡。
(2)分区治理
Eureka支持Region和Zone的概念。其中一个Region可以包含多个Zone。Eureka在启动时需要指定一个Zone名,即当前Eureka属于哪个Zone,如果不指定则属于defaultZone。Eureka Client也需要指定Zone,Client(当与Ribbon配置使用时)在向Server获取注册列表时会优先向自己所在Zone的Eureka发请求,只有自己Zone中的Eureka全挂了才会尝试向其他Zone发请求。当获取到远程服务列表后,Client也会优先向同一个Zone的服务发起远程调用。Region和Zone可以对应于现实中的大区和机房,如在华北地区有10个机房,在华南地区有20个机房,那么分别为Eureka指定合理的Region和Zone能有效避免跨机房调用,而一个地区的Eureka坏掉也不会导致整个该地区的服务都不可用。
(3)Ribbon软负载均衡
Ribbon在工作时分成两步:第一步先选择Eureka Server,优先选择同一个Zone且负载较少的Server,第二步再根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon默认提供了三种策略:轮询、断路器和根据响应时间加权。
(4)声明式HTTP RESTful客户端Feign
Feign与Apache Http Client这类客户端最大的不同,是它允许通过定义接口的形式构造HTTP请求,不需要手动拼参数,使用起来与正常的本地调用没有什么区别:
@FeignClient(name = "ea")
public interface AdvertGroupRemoteService {

@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)
AdvertGroupVO findByGroupId(@PathVariable("groupId") Integer adGroupId);

}
这里只需要调用AdvertGroupRemoteService.findByGroupId()方法就能完成向目标主机发送HTTP请求并封装返回结果的效果。
(5)断路器
断路器(Cricuit Breaker)是一种能够在远程服务不可用时自动熔断(打开开关),并在远程服务恢复时自动恢复(闭合开关)的设施,Spring Cloud通过Netflix的Hystrix组件提供断路器、资源隔离与自我修复功能。
(6)资源隔离
Hystrix对每一个依赖服务都配置了一个线程池,对依赖服务的调用会在线程池中执行。例如,我们设计服务I的线程池大小为20,那么Hystrix会最多允许有20个容器线程调用服务I,如果超出20,Hystrix会拒绝并快速失败。这样即使服务I长时间未响应,容器最多也只能堵塞20个线程,剩余80个线程仍然可以处理用户请求。
(7)快速失败
快速失败是防止资源耗尽的关键一点。当Hystrix发现在过去某段时间内对服务I的调用出错率达到某个阈值时,Hystrix就会“熔断”该服务,后续任何发向服务I的请求都会快速失败,而不是白白让调用线程去等待。
(8)自我修复
处于熔断状态的服务,在经过一段时间后,Hystrix会让其进入“半关闭”状态,即允许少量请求通过,然后统计调用的成功率。如果这个请求能成功,Hystrix会恢复该服务,从而达到自我修复的效果。其中,在服务被熔断到进入半关闭状态之间的时间,就是留给开发人员排查错误并恢复故障的时间,开发人员可以通过监控措施得到提醒并线上排查。
(9)监控方案
监控是保障分布式系统健康运行必不可少的方案。基于Spring Cloud,我们可以从两个纬度进行监控:Hystrix断路器的监控和每个服务监控状况的监控。
图1-10是Hystrix提供的Dashboard图形化监控。
可见图1-10中监控信息应有尽有(调用成功率、平时响应时间、调用频次、断路器状态等)。可以通过编程的方式定时获取该信息,并在断路器熔断时通过短信、邮件等方式通知开发者。
Hystrix的监控数据默认保存在每个实例的内存中,Spring Boot提供了多种方式,可以导入到Redis、TSDB以供日后分析使用。
image.png
除此之外,Spring Cloud还提供了对单个实例的监控,如图1-11所示。其中包含了接口调用频次、响应时间、JVM状态、动态日志等各种开发者关心的信息。

Spring Cloud的版本介绍

(1)版本命名
之前提到过,Spring Cloud是一个拥有诸多子项目的大型综合项目,原则上其子项目也都维护着自己的发布版本号。每一个Spring Cloud的版本都会包含不同的子项目版本,为了管理每个版本的子项目清单,避免版本名与子项目的发布号混淆,没有采用版本号的方式,而是通过命名的方式。这些版本采用了伦敦地铁站的名字,根据字母表的顺序来对应版本时间顺序,比如:最早的Release版本为Angel,第二个Release版本为Brixton,依此类推。
(2)版本号
经过上面的解释,不难猜出,Angel.SR6和Brixton.SR5中的SR6、SR5就是版本号了。
当一个版本的Spring Cloud项目的发布内容积累到临界点或者一个严重bug解决后,就会发布一个“service releases”版本,简称SRX版本,其中X是一个递增数字。
(3)当前版本
我们在选择Spring Boot与Spring Cloud版本的时候,还是需要尽可能按照Spring Cloud官方版本依赖关系来选择:

  • Brixton版本对应Spring Boot 1.3.x;
  • Camden版本对应Spring Boot 1.4.x;
  • Dalston版本对应Spring Boot 1.5.x。

image.png
在开始正式介绍每个项目之前,需要准备如表1-2所示的环境。
image.png

1.3 小结

微服务架构将一个应用拆分成多个独立的、具有业务属性的服务,每个服务运行在不同的进程中,服务与服务之间通过轻量级的通信机制互相协作、互相配合,从而为终端用户提供业务价值。因此,微服务架构强调的是一种独立开发、独立测试、独立部署、独立运行的高度自治的架构模式,也是一种更灵活、更开放、更松散的演进式架构。
希望通过本章所介绍的微服务的定义、核心特征、优缺点,以及微服务实现框架Spring Cloud的综合介绍,大家能够对微服务以及Spring Cloud有全面的了解,接下来的章节将逐一、详细介绍Spring Cloud的各个组件。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

华章出版社

官方博客
官网链接