详情
我们针对图书内容开发了在线编程练习题,并提供了在线编程环境,您可以边读书,边练习,在线编程,双效合一! 购买【异步社区VIP会员】或直接购买以下图书的【e读版电子书】后,即可在线畅读全书,并可通过章节末尾入口进入在线编程练习!了解更多精品图书在线编程实验课:https://www.epubit.com/topicsDetails?id=877f112b-febb-49f4-b203-ec6432852759
我们针对图书内容开发了在线编程练习题,并提供了在线编程环境,您可以边读书,边练习,在线编程,双效合一! 购买【异步社区VIP会员】或直接购买以下图书的【e读版电子书】后,即可在线畅读全书,并可通过章节末尾入口进入在线编程练习!了解更多精品图书在线编程实验课:https://www.epubit.com/topicsDetails?id=877f112b-febb-49f4-b203-ec6432852759
书名:深入理解Spring Cloud与微服务构建(第2版)
ISBN:978-7-115-51488-2
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 方志朋
责任编辑 张 爽
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书共分为18章,全面涵盖了通过Spring Cloud构建微服务的相关知识点。第1、2章详细介绍了微服务架构和Spring Cloud。第3、4章讲解了通过Spring Cloud构建微服务的准备工作。第5~14章以案例为切入点,讲解了通过Spring Cloud构建微服务的基础组件,包括Eureka、Ribbon、Feign、Hystrix、Zuul、Gateway、Consul、Config、Sleuth、Admin等组件。第15~17章讲述了使用Spring Cloud OAuth2来保护微服务系统的相关知识。第18章用一个综合案例全面讲解了如何使用Spring Cloud构建微服务,可用于实际开发中。
本书既适合Spring Cloud初学者使用,也适合正在做微服务实践的架构师或将要实施微服务的团队参考,同时也可作为高等院校计算机相关专业的师生用书和培训学校的教材。
在业务驱动的时代,企业大多急于解决效率、成本和质量的问题,开发团队的不稳定,导致业务设计、技术架构和代码脉络的不连续性。企业领导对技术储备的不重视,导致企业内部重业务、轻技术,很多研发人员缺乏设计意识。各个行业对软件系统的诉求越来越多,导致软件系统规模不断增大、复杂度不断增加,最终的结果是系统难以扩展、维护、重构、跟踪、评估工期。软件在发展过程中会面临遗留系统的种种问题,但“外科手术”治不好遗留系统复杂的病症,这是架构需要演进的根源之一。
复杂系统的各个组成部分自然趋向于混乱无序,越混乱,越稳定。如果要打破混乱、建立秩序,根据熵增定律,就要赋予系统一定的力量或者能量。混乱是事物最自然的状态,秩序却不是,但是人们希望有秩序,所以要付出代价建立制度,并维护秩序。
在这个背景下,软件系统的架构一步步演进和发展,经历了单体架构、分布式应用架构、微服务架构、服务网格架构、Serverless架构……其中,单体架构经历了简单单体时期(例如经典的JSP)、MVC分层时期(各种MVC框架受到追捧)、前后端分离时期。从整体上看,这一次次的演进是软件垂直和水平方向上的拆分,屏蔽了底层与重新定位。在演进过程中,软件开发人员的关注点越来越远离底层的部分,更多地关注上层简单的架构,技术团队的职能划分也越来越清晰。这使得软件的研发过程更高效,质量更可控,工期也更易评估。从这个角度来看,作为技术人员,我们都需要用历史的眼光去看技术的发展,拥抱变化。
微服务架构不是银弹,就像最近不断被提起的中台不能解决所有企业的问题。我们有时会存在某种认知的误区,对成功案例方法本身的关注甚于对问题本身的关注。企业的健康发展在于发现、分析和解决自身的问题,而不是盲目模仿成功的企业。
基于以上的警示,是否要在团队内部进行微服务实践?微服务落地该如何选型呢?作为一个技术人员,选择需要慎重。希望Spring Cloud能够帮你解决当前的问题,而不只是做一个简单的门户或者网站,因为没有必要为一两个简单的管理系统来维护Spring Cloud的一整套组件。在为新系统和遗留系统选择使用Spring Cloud前,我们需要分析当前面临的问题。
我见过一些团队对选型的背景、原因和目的并不是十分了解,就在新项目中直接使用Spring Cloud,只是为了不让自己与当前服务化阶段受追捧的微服务架构潮流脱节。很少有人在选型前对自己软件系统的规模、所在企业的底层资源自动化的程度、技术团队的组织形式、当前业务所面临的问题、团队的技术栈,以及引入Spring Cloud的成本等进行关注和研究。
我也见过一些团队在遗留系统复杂度高、业务耦合严重、模块划分不清晰,甚至模块拆分在垂直和水平层面都不彻底时,整个系统臃肿不堪,团队迫不得已用Spring Cloud将遗留系统强势进行拆分,在将复杂系统迁移到Spring Cloud的过程中遇到了很多问题。
《深入理解Spring Cloud与微服务构建(第2版)》深入浅出地讲解了Spring Cloud生态组件,包括服务注册发现组件Eureka、配置中心Spring Cloud Config、容错组件Hystrix、接入赋能组件Zuul、路由负载均衡组件(高可用性和稳定性)Ribbon等,使读者能够熟悉Spring Cloud各组件的作用和使用方法。
此外,本书还对一些技术点举一反三,例如在讲解RestTemplate作为网络请求时,提到其他Spring Template,包括JdbcTemplate和JmsTemplate等。本书实用性强,代码示例全面,能够使读者在技术学习方法与认知上有一定的转变和提升。
我相信无论是正在学习Spring Cloud的朋友,还是正在推进或选型Spring Cloud落地的团队,都能从本书中有所收获。
中国的近现代史是一段“师夷长技以制夷”的历史,在如今信息技术和互联网技术快速发展的时代,我们不能只停留于学习和模仿,更要发现、耕耘、创新。在此与大家共勉!
徐凌云 高级架构师
2019年夏 于湖北
作为Java语言的落地微服务框架,Spring Cloud已经在各大企业普遍应用,各大云厂商也支持Spring Cloud微服务框架的云产品。可以说,Spring Cloud微服务框架已经应用到了各大行业之中,并成为Java开发者的必备技能之一,熟练掌握Spring Cloud是面试者的加分项。
Spring Cloud由Spring Cloud社区维护,并且在Pivatol和Netflix两大公司的推动下飞速发展。随着Eureka的闭源,虽然Netflix OSS等组件进入维护期,不再提供新功能,但Spring Cloud微服务框架并没有受到显著影响,而是被越来越多的企业和开发者所接受。阿里巴巴推出的Nacos和Sentinel等组件已经加入Spring Cloud孵化器项目,未来极有可能替代Netflix OSS,因此Spring Cloud是一个极具生命力的微服务框架。
在本书第1版出版后不到一年的时间,我便开始着手准备第2版,在短时间内更新第1版的原因有以下几点。
第一,为了快速跟进Spring Cloud新版本。本书使用的Spring Cloud版本为Greenwich,Spring Boot版本为2.1.0。众所周知,Spring Cloud最大的特色是开源,它是由众多优秀的开源组件封装、集成的。比如,它集成了Netflix OSS组件和Nacos组件等;Spring Cloud社区十分活跃,吸引了众多优秀的开发者加入其项目开发中,因此Spring Cloud的版本迭代非常快。本书第1版使用的Spring Cloud版本为Dalston,Spring Boot版本为1.5.3。在短短一年多的时间内,Spring Cloud已经迭代了Edgware、Finchley和Greenwich三大版本,对应的Spring Boot版本分别为1.5.x、2.0.x和2.1.x。2.0.x版本的Spring Boot更新幅度较大,支持Webflux响应式编程和Http2等新特性。Spring Cloud基于Spring Boot,所以Spring Cloud的Finchley版本是一个变动较大的版本。本书使用的Greenwich版本是基于Finchley的一个小迭代。
第二,使用Spring Cloud作为微服务框架的大多数企业都使用Consul作为服务注册组件。Consul为微服务的元数据提供了强一致性的保障,支持多个数据中心,这是它相对于Eureka 1.0的优点。此外,Eureka的闭源使得作为注册中心的Consul越来越重要,所以本书第2版详细介绍了Consul。
第三,Spring Cloud的第一代网关Zuul是一个阻塞式网关,在性能方面有诸多不足。Spring Cloud在Finchley版本中推出了新一代网关Spring Cloud Gateway。Spring Cloud Gateway是非阻塞式网关,与Zuul相比,性能有较大提升。
第四,很多组件在新版本中的变动较大,如Sleuth、Admin和Security等。部分读者反馈,第1版中的源码在更新版本后出现了无法运行的现象,因此内容更新和升级迫在眉睫。
本书共分为18章,各章主要内容如下。
第1章介绍了什么是微服务、为什么需要微服务、微服务的优缺点和面临的挑战,并且将单体架构的系统和微服务架构的系统进行了比较。
第2章主要介绍微服务应该具备的功能以及Spring Cloud的基本组件,最后介绍了 Spring Cloud与Dubbo、Kubernetes之间的差异。
第3、4章介绍了构建微服务的准备工作:开发环境的构建和Spring Boot的使用。其中,第3章介绍了开发环境的构建,包括JDK的安装、IDEA和Maven的使用等;第4章介绍了Spring Boot的基本使用方法,包括Spring Boot的特点、用IDEA创建一个Spring Boot项目、Spring Boot配置文件详情、Spring Boot的Actuator模块,以及Spring Boot集成JPA、Redis和Swagger2等。
第5~9章介绍了Spring Cloud框架的基础模块—Spring Cloud Netflix模块,涵盖了Spring Cloud构建微服务的基础组件。诸如Eureka、Ribbon、Feign、Hystrix和Zuul等组件为微服务系统提供了基本的服务治理能力。这些章以案例为切入点,由浅入深介绍这些组件,并从源码的角度分析这些组件的工作原理。
第10章介绍了Spring Cloud的第二代网关Gateway。Gateway在性能上比Zuul要优异很多,是Spring Cloud的新一代网关。
第11章介绍了服务注册中心Consul,详细讲解了如何使用Consul进行服务注册和发现,以及如何使用Consul作为分布式配置中心。
第12章介绍了分布式配置中心Spring Cloud Config,详细讲解了Config Server如何从本地仓库和远程Git仓库读取配置文件,以及如何构建高可用的分布式配置中心和使用消息总线刷新配置文件。
第13章介绍了链路追踪组件Spring Cloud Sleuth,包括微服务系统为什么需要链路追踪组件,并以案例的形式详细介绍了如何在Spring Cloud微服务系统中使用链路追踪,以及如何传输、存储和展示链路数据。
第14章以案例的形式介绍了Spring Boot Admin,包括Spring Boot Admin在微服务系统中的应用、在Spring Boot Admin中集成安全组件。
第15~17章介绍了Spring Cloud微服务系统的安全验证模块,包括Spring Boot Security组件和Spring Cloud OAuth2模块。第15章详细介绍了如何在Spring Boot应用中使用Spring Boot Security;第16章介绍了如何在Spring Cloud微服务系统中使用Spring Cloud OAuth2来保障微服务系统的安全;第17章介绍了如何在Spring Cloud微服务系统中使用Spring Cloud OAuth2和JWT来保护微服务的系统安全。
第18章以一个综合案例介绍了使用Spring Cloud构建微服务系统的全过程,该案例是对全书内容的总结和提炼。
感谢我的家人在我写作本书过程中给予我的支持和鼓励。
感谢我的大学导师王为民教授对我的指导和培养。
感谢编辑张爽在本书写作和出版过程中所做的工作。
感谢各位读者和朋友的厚爱!
方志朋
2019年夏
本书由异步社区出品,社区(https://www.epubit.com/)为您提供相关资源和后续服务。
本书提供源代码文件,请在异步社区本书页面中点击,跳转到下载界面,按提示进行操作即可。注意:为保证购书读者的权益,该操作会给出相关提示,要求输入提取码进行验证。
如果您是教师,希望获得教学配套资源,请在社区本书页面中直接联系本书的责任编辑。
作者和编辑尽最大努力来确保书中内容的准确性,但难免会存在疏漏。欢迎您将发现的问题反馈给我们,帮助我们提升图书的质量。
当您发现错误时,请登录异步社区,按书名搜索,进入本书页面,点击“提交勘误”,输入勘误信息,点击“提交”按钮即可。本书的作者和编辑会对您提交的勘误进行审核,确认并接受后,您将获赠异步社区的100积分。积分可用于在异步社区兑换优惠券、样书或奖品。
我们的联系邮箱是contact@epubit.com.cn。
如果您对本书有任何疑问或建议,请您发邮件给我们,并请在邮件标题中注明本书书名,以便我们更高效地做出反馈。
如果您有兴趣出版图书、录制教学视频,或者参与图书翻译、技术审校等工作,可以发邮件给我们;有意出版图书的作者也可以到异步社区在线提交投稿(直接访问www.epubit.com/selfpublish/submission即可)。
如果您是学校、培训机构或企业,想批量购买本书或异步社区出版的其他图书,也可以发邮件给我们。
如果您在网上发现有针对异步社区出品图书的各种形式的盗版行为,包括对图书全部或部分内容的非授权传播,请您将怀疑有侵权行为的链接发邮件给我们。您的这一举动是对作者权益的保护,也是我们持续为您提供有价值的内容的动力之源。
“异步社区”是人民邮电出版社旗下IT专业图书社区,致力于出版精品IT技术图书和相关学习产品,为作译者提供优质出版服务。异步社区创办于2015年8月,提供大量精品IT技术图书和电子书,以及高品质技术文章和视频课程。更多详情请访问异步社区官网https://www.epubit.com。
“异步图书”是由异步社区编辑团队策划出版的精品IT专业图书的品牌,依托于人民邮电出版社近30年的计算机图书出版积累和专业编辑团队,相关图书在封面上印有异步图书的LOGO。异步图书的出版领域包括软件开发、大数据、AI、测试、前端、网络技术等。
异步社区
微信服务号
随着互联网技术的飞速发展,目前全球超过一半的人口在使用互联网产品,人们的生活随着互联网的发展,发生了翻天覆地的变化。各行各业都在应用互联网,国家政策也在大力支持互联网的发展。随着越来越多的用户参与,业务场景越来越复杂,传统的单体架构已经很难满足互联网技术的发展要求。这主要体现在两方面,一是随着业务复杂度的提高,代码的可维护性、扩展性和可读性在降低;二是维护系统的成本、修改系统的成本在提高。所以,改变单体应用架构已经势在必行。另外,随着云计算、大数据、人工智能的飞速发展,对系统架构也提出了越来越高的要求。
微服务,是著名的OO(面向对象,Object Oriented)专家Martin Fowler提出来的,用来描述将软件应用程序设计为独立部署的服务。最近两年,微服务在各大技术会议、文章、书籍上出现的频率,已经让人们意识到它对于软件领域所带来的影响力。微服务架构的系统是一个分布式系统,按业务领域划分为独立的服务单元,有自动化运维、容错、快速演进的特点,它能够解决传统单体架构系统的痛点,同时也能满足越来越复杂的业务需求。
在软件设计中,经常提及和使用经典的3层模型,即表示层、业务逻辑层和数据访问层。
虽然在软件设计中划分了经典的3层模型,但是对业务场景没有划分。一个典型的单体应用就是将所有的业务场景的表示层、业务逻辑层和数据访问层放在一个工程中,最终经过编译、打包,部署在一台服务器上。例如,典型的J2EE工程是将表示层的JSP、业务逻辑层的Service、Controller和数据访问层的Dao,打成war包,部署在Tomcat、Jetty或者其他Servlet容器中运行。经典的单体应用如图1-1所示。
▲图1-1 经典的单体应用架构
在一个小型应用的初始阶段,访问量较小,应用只需要一台服务器就能够部署所有的资源,例如将应用程序、数据库、文件资源等部署在同一台服务器上。最典型的就是LAMP系统,即服务器采用Linux系统,开发应用程序的语言为PHP,部署在Apache服务器上,采用MySQL数据库。在应用程序的初始阶段,采用这种架构的性价比是非常高的,开发速度快,开发成本低,只需要一台廉价的服务器。此时的服务器架构如图1-2所示。
▲图1-2 LAMP应用服务器示意图
在应用的初始阶段,单体架构无论是在开发速度、运维难度,还是服务器的成本上都有着显著的优势。在一个产品的前景不明确的初始阶段,用单体架构是非常明智的选择。随着应用业务的发展和业务复杂度的提高,这种架构明显存在很多的不足,主要体现在以下3个方面。
随着业务的发展,大多数公司会将单体应用进行集群部署,并增加负载均衡服务器(例如Nginx 等)。另外,还需要增加集群部署的缓存服务器和文件服务器,并将数据库读写分离,以应对用户量的增加而带来的高并发访问量。此时的系统架构如图1-3所示。
用负载均衡服务器分发高并发的网络请求,用户的访问被分派到不同的应用服务器,应用服务器的负载不再成为瓶颈,用户量增加时,添加应用服务器即可。通过添加缓存服务器来缓解数据库的数据以及数据库读取数据的压力。大多数的读取操作是由缓存完成的,但是仍然有少数读操作是从数据库读取的,例如缓存失效、实时数据等。当有大量的读写操作时,将数据库进行读写分离是一个不错的选择,例如MySQL的主从热备份,通过相关配置可以将主数据库服务器的数据同步到从数据库服务器,实现数据库的读写分离,读写分离能够改善数据库的负载能力。
▲图1-3 单体服务的集群化
这种架构有一定的处理高并发的能力,也能应对一定复杂的业务需求,改善了系统的性能,但是依然没有改变系统为单体架构的事实,此时存在的不足之处如下。
由此看见,在应用初期,单体应用在成本、开发时间和运维等方面都有明显的优势。但是随着业务量和用户量的增加,它所暴露出来的缺点也显而易见。单体架构已经不能满足复杂的业务和海量的用户系统,改变单体架构势在必行。
微服务是最近几年才出现的新名词,它在各大技术社区、博客、论坛和新闻报道中经常被提及,是程序员和架构师经常讨论的话题。的确,微服务已经是技术圈的热门话题,那么到底什么是微服务呢?微服务产生的意义又是什么呢?微服务有哪些优势和缺点?另外,微服务与SOA架构有什么关系?下面让我来为你逐一阐述。
“微服务”最初是由Martin Fowler 在2014年写的一篇文章《MicroServices》中提出来的。关于Martin Fowler的介绍,维基百科上有如下的描述。
Martin Fowler,软件工程师,也是一个软件开发方面的著作者和国际知名演说家,专注于面向对象分析与设计、统一建模语言、领域建模,以及敏捷软件开发方法,包括极限编程。主要著作有《可重用对象模型》《重构——改善既有代码的设计》《企业应用架构模式》《规划极限编程》等。
对于微服务,业界没有一个严格统一的定义,但是作为“微服务”这一名词的发明人,Martin Fowler对微服务的定义似乎更具有权威性和指导意义,他的理解如下。
简而言之,微服务架构的风格,就是将单一程序开发成一个微服务,每个微服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP RESTFUL API。这些服务围绕业务能力来划分构建的,并通过完全自动化部署机制来独立部署。这些服务可以使用不同的编程语言,以及不同数据存储技术,以保证最低限度的集中式管理。
以我个人对这段话的理解,总结微服务具有如下特点。
根据这些特点,下面来进一步阐述微服务。
微服务的“微”到底需要定义到什么样的程度,这是一个非常难以界定的概念,可以从以下3个方面来界定:一是根据代码量来定义,根据代码的多少来判断程序的大小;二是根据开发时间的长短来判断;三是根据业务的大小来划分。
根据Martin Fowler的定义,微服务的“微”是按照业务来划分的。一个大的业务可以拆分成若干小的业务,一个小的业务又可以拆分成若干更小的业务,业务到底怎么拆分才算合适,这需要开发人员自己去决定。例如微博最常见的功能是微博内容、关注和粉丝,而其中微博内容又有点赞、评论等,如何将微博这个复杂的程序划分为单个的服务,需要由开发团队去决定。
按业务划分的微服务单元独立部署,运行在独立的进程中。这些微服务单元是高度组件化的模块,并提供了稳定的模块边界,服务与服务之间没有任何的耦合,有非常好的扩展性和复用性。
传统的软件开发模式通常由UI团队、服务端团队、数据库和运维团队构成,相应地将软件按照职能划分为UI、服务端、数据库和运维等模块。通常这些开发人员各司其职,很少有人跨职能去工作。如果按照业务来划分服务,每个服务都需要独立的UI、服务端、数据库和运维。也就是说,一个小的业务的微服务需要动用一个团队的人去协作,这显然增加了团队与团队之间交流协作的成本。所以产生了跨职能团队,这个团队负责一个服务的所有工作,包括UI、服务端和数据库。当这个团队只有1~2个人的时候,就对开发人员提出了更高的要求。
按照业务划分的微服务单元独立部署,并运行在各自的进程中。微服务单元之间的通信方式一般倾向于使用HTTP这种简单的通信机制,更多的时候是使用RESTful API的。这种接受请求、处理业务逻辑、返回数据的HTTP模式非常高效,并且这种通信机制与平台和语言无关。例如用Java写的服务可以消费用Go语言写的服务,用Go写的服务又可以消费用Ruby写的服务。不同的服务采用不同的语言去实现,不同的平台去部署,它们之间使用HTTP进行通信,如图1-4所示。
▲图1-4 不同语言、不同的平台的微服务相互调用
服务与服务之间也可以通过轻量级的消息总线来通信,例如RabbitMQ和Kaf ka等。通过发送消息或者订阅消息来达到服务与服务之间通信的目的。
服务与服务通信的数据格式,一般为JSON、XML,这两种数据格式与语言、平台、通信协议无关。一般来说,JSON格式的数据比XML轻量,并且可读性也比XML要好。另外一种就是用Protobuf进行数据序列化,经过序列化的数据为二进制数据,它比JSON更轻量。用Protobuf序列化的数据为二进制数据,可读性非常差,需要反序列化才能够读懂。由于用Protobuf序列化的数据更为轻量,所以Protobuf在通信协议和数据存储上十分受欢迎。
服务与服务之间通过HTTP或者消息总线的方式进行通信,这种方式存在弊端,其通信机制是不可靠的,虽然成功率很高,但还是会有失败的时候。
在单体架构中,所有的业务都共用一个数据库。随着业务量的增加,数据库的表的数量越来越多,难以管理和维护,并且数据量的增加会导致查询速度越来越慢。例如,一个应用有这样几个业务:用户的信息、用户的账户、用户的购物车、数据报表服务等。典型的单体架构如图1-5所示。
▲图1-5 单体服务共享一个数据库
微服务的一个特点就是按业务划分服务,服务与服务之间无耦合,就连数据库也是独立的。一个典型的微服务的架构就是每个微服务都有自己独立的数据库,数据库之间没有任何联系。这样做的好处在于,随着业务的不断扩张,服务与服务不需要提供数据库集成,而是提供API接口相互调用;还有一个好处是数据库独立,单业务的数据量少,易于维护,数据库性能有着明显的优势,数据库的迁移也很方便。
另外,随着存储技术的发展,数据库的存储方式不再仅仅是关系型数据库,非关系数据库的应用也非常广泛,例如MongDB、Redis,它们有着良好的读写性能,因此越来越受欢迎。一个典型的微服务的系统,可能每一个服务的数据库都不相同,每个服务所使用的数据存储技术需要根据业务需求来选择,如图1-6所示。
▲图1-6 微服务的数据库独立
在微服务架构中,系统会被拆分为若干个微服务,每个微服务又是一个独立的应用程序。单体架构的应用程序只需要部署一次,而微服务架构有多少个服务就需要部署多少次。随着服务数量的增加,如果微服务按照单体架构的部署方式,部署的难度会呈指数增加。业务的粒度划分得越细,微服务的数量就越多,这时需要更稳定的部署机制。随着技术的发展,尤其是Docker 容器技术的推进、Kubernetes容器编排技术的发展,以及自动化部署工具(例如开源组件 Jenkins)的出现,自动化部署变得越来越简单。
自动化部署可以提高部署的效率,减少人为的控制,部署过程中出现错误的概率降低,部署过程的每一步自动化,提高软件的质量。构建一个自动化部署的系统,虽然在前期需要开发人员或者运维人员的学习,但是对于整个软件系统来说是一个全新的概念。在软件系统的整个生命周期之中,每一步是由程序控制的,而不是人为控制,软件的质量提高到了一个新的高度。随着DevOps这种全新概念的推进,自动化部署必然会成为微服务部署的一种方式。
微服务系统是按业务单元来划分服务的,服务数量越多,管理起来就越复杂,因此微服务必须使用集中化管理。目前流行的微服务框架中,例如Spring Cloud 支持使用Eureka、Zookeeper和Consul来注册服务和发现服务,另外,Etcd和Nacos等都是非常优秀的服务注册与发现组件。
分布式系统是集群部署的,由很多计算机相互协作共同构成,它能够处理海量的用户请求。当分布式系统对外提供服务时,用户是毫不知情的,还以为是一台服务器在提供服务。
分布式系统的复杂任务通过计算机之间的相互协作来完成,当然简单的任务也可以在一台计算机上完成。
分布式系统通过网络协议来通信,所以分布式系统在空间上没有任何限制,即分布式服务器可以部署不同的机房和不同的地区。
微服务架构是分布式架构,分布式系统比单体系统更加复杂,主要体现在服务的独立性和服务相互调用的可靠性,以及分布式事务、全局锁、全局Id等,而单体系统不需要考虑这些复杂性。
另外,分布式系统的应用都是集群化部署,会给数据一致性带来困难。分布式系统中的服务通信依赖于网络,网络不好,必然会对分布式系统带来很大的影响。在分布式系统中,服务之间相互依赖,如果一个服务出现了故障或者是网络延迟,在高并发的情况下,会导致线程阻塞,在很短的时间内该服务的线程资源会消耗殆尽,最终使得该服务不可用。由于服务的相互依赖,可能会导致整个系统的不可用,这就是“雪崩效应”。为了防止此类事件的发生,分布式系统必然要采取相应的措施,例如“熔断机制”。
为了防止“雪崩效应”事件的发生,分布式系统采用了熔断机制。在用Spring Cloud构建的微服务系统中,采用了熔断器(即Hystrix组件的Circuit Breaker)去做熔断。
例如在微服务系统中,有a、b、c、d、e、f、g、h等多个服务,用户的请求通过网关后,再到具体的服务,服务之间相互依赖,例如服务b依赖于服务f,一个对外暴露的API接口需要服务b和服务f相互协作才能完成。服务之间相互依赖的架构图如图1-7所示。
▲图1-7 服务之间相互依赖
如果此时服务b出现故障或者网络延迟,在高并发的情况下,服务b会出现大量的线程阻塞,有可能在很短的时间内线程资源就被消耗完了,导致服务b的不可用。如果服务b为较底层的服务,会影响到其他服务,导致其他服务会一直等待服务b的处理。如果服务b迟迟不处理,大量的网络请求不仅仅堆积在服务b,而且会堆积到依赖于服务b的其他服务。而因服务b出现故障影响的服务,也会影响到依赖于因服务b出现故障影响的服务的其他服务,从而由服务b开始,影响到整个系统,导致整个系统的不可用。这是一件非常可怕的事,因为服务器运营商的不可靠,必然会导致服务的不可靠,而网络服务商的不可靠性,也会导致服务的不可靠。在高并发的场景下,稍微有点不可靠,由于故障的传播性,会导致大量的服务不可用,甚至导致整个系统崩溃。
为了解决这一难题,微服务架构引入了熔断机制。当服务b出现故障,请求失败次数超过设定的阀值之后,服务b就会开启熔断器,之后服务b不进行任何的业务逻辑操作,执行快速失败,直接返回请求失败的信息。其他依赖于b的服务就不会因为得不到响应而线程阻塞,这时除了服务b和依赖于服务b的部分功能不可用外,其他功能正常。熔断服务 b 如图 1-8所示。
▲图1-8 将服务b熔断
熔断器还有另一个机制,即自我修复的机制。当服务b熔断后,经过一段时间,半打开熔断器。半打开的熔断器会检查一部分请求是否正常,其他请求执行快速失败,检查的请求如果响应成功,则可以判定服务b正常了,就会关闭服务b的熔断器;如果服务b还不正常,则继续打开熔断器。这种自我熔断机制和自我修复机制在微服务架构中有着重要的意义,一方面,它使程序更加健壮;另一方面,为开发和运维减少很多不必要的工作。
最后,熔断组件往往会提供一系列的监控,例如服务可用与否、熔断器是否被打开、目前的吞吐量、网络延迟状态的监控等,从而很容易让开发人员和运维人员实时地了解服务的状况。
相对于单体服务来说,微服务具有很多的优势,主要体现在以下方面。
(1)将一个复杂的业务分解成若干小的业务,每个业务拆分成一个服务,服务的边界明确,将复杂的问题简单化。服务按照业务拆分,编码也是按照业务来拆分,代码的可读性和可扩展性增加。新人加入团队,不需要了解所有的业务代码,只需要了解他所接管的服务的代码,新人学习时间成本减少。
(2)由于微服务系统是分布式系统,服务与服务之间没有任何的耦合。随着业务的增加,可以根据业务再拆分服务,具有极强的横向扩展能力。随着应用的用户量的增加,并发量增加,可以将微服务集群化部署,从而增加系统的负载能力。简而言之,微服务系统的微服务单元具有很强的横向扩展能力。
(3)服务与服务之间通过HTTP网络通信协议来通信,单个微服务内部高度耦合,服务与服务之间完全独立,无耦合。这使得微服务可以采用任何的开发语言和技术来实现。开发人员不再被强迫使用公司以前的技术或者已经过时的技术,而是可以自由选择最适合业务场景的或者最适合自己的开发语言和技术,提高开发效率、降低开发成本。
(4)如果是一个单体的应用,由于业务的复杂性、代码的耦合性,以及可能存在的历史问题。在重写一个单体应用时,要求重写的应用的人员了解所有的业务,所以重写单体应用是非常困难的,并且重写风险也较高。如果是微服务系统,由于微服务系统是按照业务的进行拆分的,并且有坚实的服务边界,所以重写某个服务就相当于重写某一个业务的代码,非常简单。
(5)微服务的每个服务单元都是独立部署的,即独立运行在某个进程里。微服务的修改和部署对其他服务没有影响。试想,假设一个应用只有一个简单的修改,如果是单体架构,需要测试和部署整个应用;而如果采用微服务架构,只需要测试并部署被修改的那个服务,这就大大减少了测试和部署的时间。
(6)微服务在CAP理论中采用的是AP架构,即具有高可用和分区容错的特点。高可用主要体现在系统7 × 24小时不间断的服务,它要求系统有大量的服务器集群,从而提高了系统的负载能力。另外,分区容错也使得系统更加健壮。
凡事都有两面性,微服务也不例外,微服务相对于单体应用来说具有很多的优势,当然也有它的不足,主要体现在如下方面。
构建一个微服务系统并不是一件容易的事,微服务系统是分布式系统,构建的复杂度远远超过单体系统,开发人员需要付出一定的学习成本去掌握更多的架构知识和框架知识。服务与服务之间通过HTTP协议或者消息传递机制通信,开发者需要选出最佳的通信机制,并解决网络服务较差时带来的风险。
此外,服务与服务之间相互依赖,如果修改某一个服务,会对另一个服务产生影响,如果掌控不好,会产生不必要的麻烦。由于服务的依赖性,测试也会变得复杂,比如修改一个比较基础的服务,可能需要重启所有的服务才能完成测试。
微服务架构所设计的系统是分布式系统。分布式系统有一个著名的CAP 理论,即同时满足“一致性”“可用性”和“分区容错”是一件不可能的事。CAP理论是由Eric Brewer在2000年PODC会议上提出的,该理论在两年后被证明成立。CAP理论告诉架构师不要妄想设计出同时满足三者的系统,应该有所取舍,设计出适合业务的系统。CAP理论如图1-9所示。
▲图1-9 CAP理论示意图
在分布式系统中,P是基本要求,而单体服务是CA系统。微服务系统通常是一个AP系统,即同时满足了可用性和分区容错。这就有了一个难题:在分布式系统中如何保证数据的一致性?这就是大家经常讨论的分布式事务。
在微服务系统中,每个服务都是独立的进程单元,每个服务都有自己的数据库。通常情况下,只有关系型数据库在特定的数据引擎下才支持事务,而大多数非关系型数据库是不支持事务的,例如MongDB是不支持事务的,而Redis是支持事务的。在微服务架构中,分布式事务一直是一个难以解决的问题,业界给出了很多解决办法,比如两阶段提交、三阶段提交、TCC等。本书将介绍两阶段提交。
网上购物在日常生活中是一个非常普通的场景,假设我在淘宝上购买了一部手机,需要从我的账户中扣除1000元钱,同时手机的库存数量需要减1。当然需要在卖方的账户中加1000元钱,为了使案例简单化,暂时不用考虑。
如果这是一个单体应用,并且使用支持事务的MySQL数据库(InnoDB数据库引擎才支持事务),我们可能这样写代码:
@Transactional
public void update() throws RuntimeException{
updateAccountTable(); //更新账户表
updateGoodsTable(); //更新商品表
}
如果是微服务架构,账户是一个服务,而商品是一个服务,这时不能用数据库自带的事务,因为这两个数据表不在一个数据库中。因此常常用到两阶段提交,两阶段提交的过程如图1-10所示。
第一阶段,service-account 发起一个分布式事务,交给事务协调器TC处理,事务协调器TC向所有参与的事务的节点发送处理事务操作的准备操作。所有的参与节点执行准备操作,将Undo和Redo信息写进日志,并向事务管理器返回准备操作是否成功。
▲图1-10 两阶段提交示意图
第二阶段,事务管理器收集所有节点的准备操作是否成功,如果都成功,则通知所有的节点执行提交操作;如果有一个失败,则执行回滚操作。
两阶段提交,将事务分成两部分能够大大提高分布式事务成功的概率。如果在第一阶段都成功了,而执行第二阶段的某一个节点失败,仍然导致数据的不准确,这时一般需要人工去处理,这就是当初在第一步记录日志的原因。另外,如果分布式事务涉及的节点很多,某一个节点的网络出现异常会导致整个事务处于阻塞状态,大大降低数据库的性能。所以一般情况下,尽量少用分布式事务。
将一个完整的系统拆分成很多个服务,是一件非常困难的事,因为这涉及了具体的业务场景,比命名一个类更加困难。对于微服务的拆分原则,Martin Fowler给出的建议是;服务是可以被替换和更新的。也就是服务和服务之间无耦合,任何一个服务都可以被替换,服务有自己严格的边界。当然这个原则很抽象,根据具体的业务场景来拆分服务,需要依靠团队人员对业务的熟悉程度和理解程度,并考虑与已有架构的冲突、业务的扩展性、开发的风险和未来业务的发展等诸多因素。
领域驱动设计是一个全新的概念,也是一个比较理想的微服务拆分的理念。领域驱动设计通过代码和数据分析找到合理的切分点,并通过数据分析来判断服务的划分边界和划分粒度。过去,在中国很少有公司去落地领域驱动设计这个理念,随着微服务的发展,这一理念在以后有可能会更多地被接受。
一个简单的单体系统可能只需要将程序集群部署并配置负载均衡服务器即可,而部署一个复杂的微服务架构的系统就复杂得多。因为每一个微服务可能还涉及比较底层的组件,例如数据库、消息中间件等。微服务系统往往由数量众多的服务构成,例如Netflix公司有大约600个服务,而每个服务又有大量的实例。微服务系统需要对每个服务进行治理、监控和管理等,而每个服务有大量的配置,还需要考虑服务的启动顺序和启动时机等。
部署微服务系统,需要开发人员或者运维人员对微服务系统有足够强的控制力。随着云计算和云服务器的发展,部署微服务系统并不是一件难事,例如使用PaaS系统、使用Docker 编排等。这就是人们往往提到微服务,就会想到Docker和DevOps的原因。其中,微服务是核心;Docker为容器技术,是微服务最佳部署的容器;DevOps是一种部署手段或理念。它们的关系如图1-11所示。
▲图1-11 微服务、Docker、DevOps之间的关系
SOA即面向服务的架构,这种架构在20年前就已经被提出了。SOA往往与企业服务总线(ESB)联系在一起,主要原因在于SOA 的实施思路是根据ESB 模式来整合集成大量单一庞大的系统,这是SOA主要的落地方式。然而,SOA在过去20年并没有取得成功。在谈到微服务时,人们很容易联想到它是一个面向服务的架构。的确,微服务的概念提出者Martin Fowler没有否认这一层关系。
微服务相对于和ESB联系在一起的SOA显然轻便敏捷得多,微服务将复杂的业务组件化,实际也是一种面向服务思想的体现。对于微服务来说,它是SOA的一种实现,但是它比ESB实现的SOA更加轻便、敏捷和简单。
软件设计就好比建筑设计。Architect这个词在建筑学中是“建筑师”的意思,而在软件领域里则是“架构师”的意思,可见它们确实有相似之处。无论是建筑师还是架构师,他们都希望把作品设计出自己的特色,并且更愿意把创造出的东西被称为艺术品。然而现实却是,建筑设计和软件设计有非常大的区别。建筑师设计并建造出来的建筑往往很难有变化,除非拆了重建。而架构师设计出来的软件系统,为了满足产品的业务发展,在它的整个生命周期中,每一个版本都有很多的变化。
软件设计每一个版本都在变化,所以软件设计应该是渐进式发展。软件从一开始就不应该被设计成微服务架构,微服务架构固然有优势,但是它需要更多的资源,包括服务器资源、技术人员等。追求大公司的技术解决方案,刻意地追求某个新技术,企图使用技术解决所有的问题,这些都是软件设计的误区。
技术应该是随着业务的发展而发展的,任何脱离业务的技术是不能产生价值的。在初创公司,业务很单一时,如果在LAMP单体构架够用的情况下,就应该用LAMP,因为它开发速度快,性价比高。随着业务的发展,用户量的增加,可以考虑将数据库读写分离、加缓存、加复杂均衡服务器、将应用程序集群化部署等。如果业务还在不断发展,这时可以考虑使用分布式系统,例如微服务架构的系统。不管使用什么样的架构,驱动架构的发展一定是业务的发展,只有当前架构不再适合当前业务的发展,才考虑更换架构。
在微服务架构中,有三大难题,那就是服务故障的传播性、服务的划分和分布式事务。在微服务设计时,一定要考虑清楚这三个难题,从而选择合适的框架。目前比较流行的微服务解决方案有Spring社区的Spring Cloud和Google公司的Kubernetes容器编排等。不管使用哪一种框架或者工具,都需要考虑这三大难题。为了解决服务故障的传播性,一般的微服务框架都有熔断机制组件。另外,服务的划分没有具体的划分方法,一般来说根据业务来划分服务,领域驱动设计具有指导作用。最后,分布式事务一般的解决办法就是两阶段提交或者三阶段提交,不管使用哪一种都存在事务失败,导致数据不一致的情况,关键时刻还得人工恢复数据。总之,微服务的设计一定是渐进式的,并且是随着业务的发展而发展的。
Spring Cloud作为Java语言的微服务框架,它依赖于Spring Boot,有快速开发、持续交付和容易部署等特点。Spring Cloud的组件非常多,涉及微服务的方方面面,并在开源社区Spring和Netflix、Pivotal两大公司的推动下越来越完善。本章主要介绍Spring Cloud,将从以下方面来讲解。
微服务,可以拆分为“微”和“服务”二字。“微”即小的意思,那到底多小才算“微”呢?可能不同的团队有不同的答案。从参与微服务的人数来讲,单个微服务从架构设计、代码开发、测试、运维的人数加起来是8~10人才算“微”。那么何为“服务”呢?按照“微服务”概念提出者Martin Fowler给出的定义:“服务”是一个独立运行的单元组件,每个单元组件运行在独立的进程中,组件与组件之间通常使用HTTP这种轻量级的通信机制进行通信。
微服务具有以下的特点。
微服务具有以上这些特点,那么微服务需要具备一些什么样的功能呢?微服务的功能主要体现在以下几个方面。
微服务系统由很多个单一职责的服务单元组成,例如Netflix公司的系统是由600多个微服务构成的,而每一个微服务又有众多实例。由于微服务系统的服务粒度较小,服务数量众多,服务之间的相互依赖成网状,所以微服务系统需要服务注册中心来统一管理微服务实例,方便查看每一个微服务实例的健康状态。
服务注册是指向服务注册中心注册一个服务实例,服务提供者将自己的服务信息(如服务名、IP地址等)告知服务注册中心。服务发现是指当服务消费者需要消费另外一个服务时,服务注册中心能够告知服务消费者它所要消费服务的实例信息(如服务名、IP地址等)。通常情况下,一个服务既是服务提供者,也是服务消费者。服务消费者一般使用HTTP协议或者消息组件这种轻量级的通信机制来进行服务消费。服务的注册与发现如图2-1所示。
▲图2-1 服务的注册与发现
服务注册中心会提供服务的健康检查方案,检查被注册的服务是否可用。通常一个服务实例注册后,会定时向服务注册中心提供“心跳”,以表明自己还处于可用的状态。当一个服务实例停止向服务注册中心提供心跳一段时间后,服务注册中心会认为该服务实例不可用,会将该服务实例从服务注册列表中剔除。如果这个被剔除掉的服务实例过一段时间后继续向注册中心提供心跳,那么服务注册中心会将该服务实例重新加入服务注册中心的列表中。另外,微服务的服务注册组件都会提供服务的健康状况查看的UI界面,开发人员或者运维人员只需要登录相关的界面就可以知道服务的健康状态。
在微服务架构中,服务之间的相互调用一般是通过HTTP通信协议来实现的。网络往往具有不可靠性,为了保证服务的高可用(High Availability),服务单元往往是集群化部署的。例如将服务提供者进行集群化部署,那么服务消费者该调用哪个服务提供者的实例呢?这就涉及了服务的负载均衡。
服务的负载均衡一般最流行的做法如图2-2所示,所有的服务都向服务注册中心注册,服务注册中心持有每个服务的应用名和IP地址等信息,同时每个服务也会获取所有服务注册列表信息。服务消费者集成负载均衡组件,该组件会向服务消费者获取服务注册列表信息,并每隔一段时间重新刷新获取该列表。当服务消费者消费服务时,负载均衡组件获取服务提供者所有实例的注册信息,并通过一定的负载均衡策略(开发者可以配置),选择一个服务提供者的实例,向该实例进行服务消费,这样就实现了负载均衡。
服务注册中心不但需要定时接收每个服务的心跳(用来检查服务是否可用),而且每个服务会定期获取服务注册列表的信息,当服务实例数量很多时,服务注册中心承担了非常大的负载。由于服务注册中心在微服务系统中起到了至关重要的作用,所以必须实现高可用。一般的做法是将服务注册中心集群化,每个服务注册中心的数据实时同步,如图2-3所示。
▲图2-2 服务的负载均衡
▲图2-3 将服务注册中心高可用
微服务落地到实际项目中,服务的数量往往非常多,服务之间的相互依赖性也是错综复杂的,一个网络请求通常需要调用多个服务才能完成。如果一个服务不可用,例如网络延迟或故障,会影响到依赖于这个不可用的服务的其他服务。如图2-4所示,一个微服务系统有很多个服务,当服务F因某些原因导致了服务的不可用,来自于用户的网络请求需要调用服务F。由于服务F无响应,用户的请求都处于阻塞状态,在高并发的场景下,短时间内会导致服务器的线程资源消耗殆尽。另外,依赖于服务F的其他的服务,例如图中的服务E、服务G、服务J,也会等待服务F的响应,处于阻塞状态,导致这些服务的线程资源消耗殆尽,进而导致它们的不可用,以及依赖于它们的服务的不可用,最后导致整个系统处于瘫痪的状态也就是1.2.1节中提到的雪崩效应。
▲图2-4 服务的依赖性
为了解决分布式系统的雪崩效应,分布式系统引进了熔断器机制。熔断器(Circuit Breaker)一词来源于物理学中的电路知识,它的作用是当电路中出现故障时迅速切断电路,从而保护电路,熔断器机制如图2-5所示。当一个服务的处理用户请求的失败次数在一定时间内小于设定的阀值时,熔断器处于关闭状态,服务正常;当服务处理用户请求的失败次数大于设定的阀值时,说明服务出现了故障,打开熔断器,这时所有的请求会执行快速失败,不执行业务逻辑。当处于打开状态的熔断器时,一段时间后会处于半打开状态,并执行一定数量的请求,剩余的请求会执行快速失败,若执行的请求失败了,则继续打开熔断器;若成功了,则将熔断器关闭。
▲图2-5 熔断器机制
这种机制有着非常重要的意义,它不仅能够有效地防止系统的“雪崩”效应,还具有以下作用。
Netflix的Hystrix熔断器开源组件功能非常强大,不仅有熔断器的功能,还有熔断器的状态监测,并提供界面友好的UI,开发人员或者运维人员通过UI界面能够直观地看到熔断器的状态和各种性能指标。
微服务系统通过将资源以API接口的形式暴露给外界来提供服务。在微服务系统中,API接口资源通常是由服务网关(也称API网关)统一暴露,内部服务不直接对外提供API资源的暴露。这样做的好处是将内部服务隐藏起来,外界还以为是一个服务在提供服务,在一定程度上保护了微服务系统的安全。API网关通常有请求转发的作用,另外它可能需要负责一定的安全验证,例如判断某个请求是否合法,该请求对某一个资源是否具有操作权限等。通常情况下,网关层以集群的形式存在。在服务网关层之前,有可能需要加上负载均衡层,通常为Nginx双机热备,通过一定的路由策略,将请求转发到网关层。到达网关层后,经过一系列的用户身份验证、权限判断,最终转发到具体的服务。具体的服务经过一系列的逻辑运算和数据操作,最终将结果返回给用户,此时的架构如图2-6所示。
▲图2-6 服务网关架构图
网关层具有很重要的意义,具体体现在以下方面。
当然,网关实现这些功能,需要做高可用,否则网关很可能成为架构中的瓶颈。最常用的网关组件有Zuul和Nginx等。
在实际开发过程中,每个服务都有大量的配置文件,例如数据库的配置、日志输出级别的配置等,而往往这些配置在不同的环境中也是不一样的。随着服务数量的增加,配置文件的管理也是一件非常复杂的事。
在微服务架构中,需要有统一管理配置文件的组件,例如Spring Cloud 的Spring Cloud Config组件、阿里巴巴的Diamond、百度的Disconf、携程的Apollo等。这些配置组件所实现的功能大体相同,但是又有些差别,下面以Spring Cloud Config为例来阐述服务配置的统一管理。
如图2-7所示,大致过程如下。
▲图2-7 服务配置统一管理
对于集群化的服务,可以通过使用消息总线来刷新多个服务实例。如果服务数量较多,对配置中心需要考虑集群化部署,从而使配置中心高可用,做分布式集群。
微服务系统是一个分布式架构的系统,微服务系统按业务划分服务单元,一个微服务系统往往有很多个服务单元。由于服务单元数量很多且业务复杂,服务与服务之间的调用有可能非常复杂,一旦出现了异常和错误,就会很难去定位。所以在微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而使每个请求链路清晰可见,出了问题很快就能定位。
举个例子,如图2-8所示,在微服务系统中,一个来自用户的请求先达到前端A(如前端界面),然后通过远程调用,达到系统的中间件B、C(如负载均衡、网关等),最后达到后端服务D、E。后端经过一系列的业务逻辑计算,最后将数据返回给用户。对于这样一个请求,经历了这么多服务,怎么样将它的请求过程的数据记录下来呢?这就需要用到服务链路追踪。
▲图2-8 请求通过A、B、C、D、E
Google开源了链路追踪组件Dapper,并在2010年发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,这篇文章是业内实现链路追踪的标杆和理论基础,具有非常高的参考价值。
目前,常见的链路追踪组件有Google的Dapper、Twitter 的Zipkin,以及阿里的Eagleeye (鹰眼)等,都是非常优秀的链路追踪开源组件。
Spring Cloud是基于Spring Boot的。Spring Boot是由Pivotal团队提供的全新Web框架,它主要的特点就是简化了开发和部署的过程,简化了Spring 复杂的配置和依赖管理,通过起步依赖和内置Servlet容器能够使开发者迅速搭起一个Web工程。所以Spring Cloud在开发部署上继承了Spring Boot的一些优点,提高了在开发和部署上的效率。
Spring Cloud的首要目标就是通过提供一系列开发组件和框架,帮助开发者迅速搭建一个分布式的微服务系统。Spring Cloud是通过包装其他技术框架来实现的,例如包装开源的Netflix OSS 组件,实现了一套通过基于注解、Java配置和基于模版开发的微服务框架。Spring Cloud框架来自于Spring Resource社区,由Pivotal和Netflix两大公司和一些其他的开发者提供技术上的更新迭代。Spring Cloud提供了开发分布式微服务系统的一些常用组件,例如服务注册和发现、配置中心、熔断器、智能路由、微代理、控制总线、全局锁、分布式会话等。
(1)服务注册和发现组件Eureka
利用Eureka组件可以很轻松地实现服务的注册和发现的功能。Eureka组件提供了服务的健康监测,以及界面友好的UI。通过Eureka组件提供的UI,Eureka组件可以让开发人员随时了解服务单元的运行情况。另外Spring Cloud也支持Consul和Zookeeper,用于注册和发现服务。
(2)熔断组件Hystrix
Hystrix是一个熔断组件,它除了有一些基本的熔断器功能外,还能够实现服务降级、服务限流的功能。另外Hystrix提供了熔断器的健康监测,以及熔断器健康数据的API接口。Hystrix Dashboard组件提供了单个服务熔断器的健康状态数据的界面展示功能,Hystrix Turbine组件提供了多个服务的熔断器的健康状态数据的界面展示功能。
(3)负载均衡组件Ribbon
Ribbon是一个负载均衡组件,它通常和Eureka、Zuul、RestTemplate、Feign配合使用。Ribbon和Zuul配合,很容易做到负载均衡,将请求根据负载均衡策略分配到不同的服务实例中。Ribbon和RestTemplate、Feign配合,在消费服务时能够做到负载均衡。
(4)路由网关Zuul
路由网关Zuul有智能路由和过滤的功能。内部服务的API接口通过Zuul网关统一对外暴露,内部服务的API接口不直接暴露,防止了内部服务敏感信息对外暴露。在默认的情况下,Zuul和Ribbon相结合,能够做到负载均衡、智能路由。Zuul的过滤功能是通过拦截请求来实现的,可以对一些用户的角色和权限进行判断,起到安全验证的作用,同时也可以用于输出实时的请求日志。
上述的4个组件都来自于Netflix的公司,统一称为Spring Cloud Netflix。
(5)Spring Cloud Config
Spring Cloud Config组件提供了配置文件统一管理的功能。Spring Cloud Config包括Server端和Client端,Server 端读取本地仓库或者远程仓库的配置文件,所有的Client向Server读取配置信息,从而达到配置文件统一管理的目的。通常情况下,Spring Cloud Config和Spring Cloud Bus相互配合刷新指定Client或所有Client的配置文件。
(6)Spring Cloud Security
Spring Cloud Security是对Spring Security组件的封装,Spring Cloud Security向服务单元提供了用户验证和权限认证。一般来说,单独在微服务系统中使用Spring Cloud Security是很少见的,一般它会配合 Spring Security OAuth2 组件一起使用,通过搭建授权服务,验证Token或者JWT这种形式对整个微服务系统进行安全验证。
(7)Spring Cloud Sleuth
Spring Cloud Sleuth是一个分布式链路追踪组件,它封装了Dapper、Zipkin和Kibana等组件,通过它可以知道服务之间的相互依赖关系,并实时观察链路的调用情况。
(8)Spring Cloud Stream
Spring Cloud Stream是Spring Cloud框架的数据流操作包,可以封装RabbitMQ、ActiveMQ、Kafka、Redis等消息组件,利用Spring Cloud Stream可以实现消息的接收和发送。
上述列举了一些常用的Spring Cloud组件。一个简单的由Spring Cloud构建的微服务系统,通常由服务注册中心Eureka、网关Zuul、配置中心Config和授权服务Auth构成,架构如图2-9所示。
▲图2-9 一个简单的由Spring Cloud构建的微服务系统
Dubbo是阿里巴巴开源的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务冶理方案。Dubbo广泛用于阿里巴巴的各大站点,有很多互联网公司也在使用这个框架,它包含如下核心内容。
Dubbo框架的架构图如图2-10所示。Dubbo架构的流程如下。
(1)服务提供者向服务中心注册服务。
(2)服务消费者订阅服务。
(3)服务消费者发现服务。
(4)服务消费者远程调度服务提供者进行服务消费,在调度过程中,使用了负载均衡策略、失败容错的功能。
▲图2-10 Dubbo架构图
(5)服务消费者和提供者,在内存中记录服务的调用次数和调用时间,并定时每分钟发送一次统计数据到监控中心。
Dubbo是一个非常优秀的服务治理框架,在国内互联网公司应用广泛,它具有以下特性。
首先从微服务关注点来比较Spring Cloud和Dubbo两大服务框架,如表2-1所示。
表2-1 从微服务关注点比较Spring Cloud和Dubbo
微服务关注点 |
Spring Cloud |
Dubbo |
---|---|---|
配置管理 |
Config |
— |
服务发现 |
Eureka、Consul、Zookeeper |
Zookeeper |
负载均衡 |
Ribbon |
自带 |
网关 |
Zuul |
— |
分布式追踪 |
Spring Cloud Sleuth |
— |
容错 |
Hystrix |
不完善 |
通信方式 |
HTTP、Message |
RPC |
安全模块 |
Spring Cloud Security |
— |
Spring Cloud拥有很多的项目模块,包含了微服务系统的方方面面。Dubbo是一个非常优秀的服务治理和服务调用框架,但缺少很多功能模块,例如网关、链路追踪等。在项目模块上,Spring Cloud更具优势。
Spring Cloud的更新速度非常快,Camden.SR5版本发布于2017年2月,Camden.SR6版本发布于2017年3月,Dalston版本发布于2017年4月,Finchley版本发布于2018年6月,Greenwich版本发布于2019年2月,基本每年发布1~2次大版本,每月会发一次版本的迭代。从GitHub的代码仓库来看,Spring Cloud几乎每天都有更新。阿里巴巴于2011年10月开源了Dubbo,开源后的Dubbo发展迅速,大概每2~3个月有一次版本更新。然而,从在2013年3月开始,Dubbo暂停了版本更新,并只在2014年10月发布了一个小版本,修复了一个bug,之后长期处于版本停止更新的状态。直到2017年9月,阿里巴巴中间件部门重新组建了Dubbo团队,把Dubbo列为重点开源项目,并在2017年9~11月期间,一直保持每月一次版本更新的频率。
从学习成本上考虑,Dubbo的版本趋于稳定,文档完善,可以即学即用,没有太大难度。Spring Cloud 基于Spring Boot开发,需要开发者先学会Spring Boot。另外,Spring Cloud版本迭代快,需要快速跟进学习。Spring Cloud文档大多是英文的,要求学习者有一定的英文阅读能力。此外,Spring Cloud文档很多,不容易快速找到相应的文档。
从开发风格上来讲,Dubbo 更倾向于Spring Xml的配置方式,Dubbo官方也推荐这种方式。Spring Cloud基于Spring Boot,Spring Boot采用的是基于注解和JavaBean配置方式的敏捷开发。从开发速度上讲,Spring Cloud具有更高的开发和部署速度。
最后,Spring Cloud 的通信方式大多数是基于HTTP Restful风格的,服务与服务之间完全无关、无耦合。由于采用的是HTTP Rest,因此服务无关乎语言和平台,只需要提供相应API接口,就可以相互调用。Dubbo 的通信方式基于远程调用,对接口、平台和语言有强依赖性。如果需要实现跨平台调用服务,需要写额外的中间件,这也是Dubbox(支持HTTP协议)存在的原因。
Dubbo和Spring Cloud拥有各自的优缺点。Dubbo更易上手,并且广泛使用于阿里巴巴的各大站点,经历了“双11”期间高并发、大流量的检验,Dubbo框架非常成熟和稳定。Spring Cloud服务框架严格遵守Martin Fowler 提出的微服务规范,社区异常活跃,它很可能成为微服务架构的标准。
Kubernetes是一个容器集群管理系统,为容器化的应用程序提供部署运行、维护、扩展、资源调度、服务发现等功能。
Kubernetes是Google运行Borg大规模系统达15年之久的一个经验总结。Kubernetes结合了社区的最佳创意和实践,旨在帮助开发人员将容器打包、动态编排,同时帮助各大公司向微服务方向进行技术演进。
它具有以下特点。
Kubernetes开源免费,是Google在过去15年时间里部署、管理微服务的经验结晶,所以目前Kubernetes在技术社区也是十分火热。下面来看它提供的功能。
从Kubernetes提供的功能来看,Kubernetes完全可以成为构建和部署微服务的一个工具,它是从服务编排上实现的,而不是代码实现的。目前国外有很多知名的公司在使用Kubernetes,如Google、eBay、Pearson等。由于它的开源免费,Microsoft、VMWare、RedHat、CoreOS等公司纷纷加入并贡献代码。Kubernetes技术吸引了一大批公司和技术爱好者,它已经成为容器管理的领导者。
Spring Cloud是一个构建微服务的框架,而Kubernetes是通过对运行的容器的编排来实现构建微服务的。两者从构建微服务的角度和实现方式有很大的不同,但它们提供了构建微服务所需的全部功能。从提供的微服务所需的功能上看,两者不分上下,如表2-2所示。
表2-2 Spring Cloud与Kubernetes比较
微服务关注点 |
Spring Cloud |
Kubernetes |
---|---|---|
配置管理 |
Config |
Kubernetes ConfigMap |
服务发现 |
Eureka、Consul、Zookeeper |
Kubernetes Services |
负载均衡 |
Ribbon |
Kubernetes Services |
网关 |
Zuul |
Kubernetes Services |
分布式追踪 |
Spring Cloud Sleuth |
Open tracing |
容错 |
Hystrix |
Kubernetes Health Check |
安全模块 |
Spring Cloud Security |
— |
分布式日志 |
ELK |
EFK |
任务管理 |
Spring Batch |
Kubernetes Jobs |
Spring Cloud通过众多的类库来实现微服务系统所需的各个组件,同时不断集成优秀的组件,所以Spring Cloud组件是非常完善的。Spring Cloud基于Spring Boot框架,有快速开发、快速部署的优点。对于Java开发者来说,学习Spring Cloud的成本不高。
Kubernetes在编排上解决微服务的各个功能,例如服务发现、配置管理、负载均衡、容错等。Kubernetes不局限于Java平台,也不局限于语言,开发者可以自由选择开发语言进行项目开发。
与Kubernetes相比,Spring Cloud具有以下优点。
下面介绍Kubernetes的优点和缺点,优点如下。
Kubernetes的缺点如下。
Spring Cloud尝试从Java类库来实现微服务的所有功能,而Kubernetes尝试从容器编排上实现所有的微服务功能,两者的实现角度和方式不一样。个人觉得,两者最终的实现功能和效果上不分胜负,但从实现的方式上来讲,Kubernetes略胜一筹。Kubernetes面向DevOps人员,学习成本高。Spring Cloud有很多的类库,以Spring为基础,继承了Spring Boot快速开发的优点,为Java程序员开发微服务提供了很好的体验,学习成本也较低。所以二者比较,各有优势。没有最好的框架,也没有最好的工具,关键是要适合业务需求和满足业务场景。
本章首先介绍了微服务应该具备的功能,然后介绍了Spring Cloud和Spring Cloud的基本组件,最后介绍了Spring Cloud与Dubbo、Kubernetes之间的比较,以及它们的优缺点。Spring Cloud作为Java语言的微服务落地框架,有很多的微服务组件。为了循序渐进地学习这些组件,第3、4章将介绍构建微服务前的准备工作,这是学习Spring Cloud组件的基本前提。