Service Mesh实战:用Istio软负载实现服务网格(txt+pdf+epub+mobi电子书下载)


发布时间:2020-10-30 16:53:40

点击下载

作者:周遥

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Service Mesh实战:用Istio软负载实现服务网格

Service Mesh实战:用Istio软负载实现服务网格试读:

作者简介

周遥

挖财中间件架构师,原阿里巴巴中间件团队技术专家,8年分布式架构经验,三项国家发明专利,在软负载领域拥有相当丰富的经验,阿里巴巴软负载核心产品VIPServer原作者。

个人邮箱:sefler@126.com

网站:htp://seflerzhou.net内容简介

本书为网格服务技术的实战详解图书。作者以初学者角度展示软负载在分布式架构中承担的角色,引入容器时代主角Kubernetes;再从路由层面全面展开对Service Mesh与Istio的系统介绍和深入剖析,包括其功能与特色;最后通过源码剖析从实现细节上分析Istio的几大关键设计。不论你是刚开始接触软负载的初学者,还是有一定经验的架构师,都可以在这本细致入微的图书中找到想要的实用内容。

未经许可,不得以任何方式复制或抄袭本书之部分或全部内容。

版权所有,侵权必究。

图书在版编目(CIP)数据

Service Mesh实战:用Istio软负载实现服务网格/周遥著.—北京:电子工业出版社,2019.5

ISBN 978-7-121-36192-0

Ⅰ.①S… Ⅱ.①周… Ⅲ.①互联网络-网络服务器 Ⅳ. ①TP368.5

中国版本图书馆CIP数据核字(2019)第057508号

策划编辑:张春雨

责任编辑:张春雨

印刷:

装订:

出版发行:电子工业出版社

北京市海淀区万寿路173信箱 邮编:100036

开本:787×980 1/16 印张:17.5 字数:420千字

版次:2019年5月第1版

印次:2019年5月第1次印刷

定价:75.00元

凡所购买电子工业出版社图书有缺损问题,请向购买书店调换。若书店售缺,请与本社发行部联系,联系及邮购电话:(010)88254888,88258888。

质量投诉请发邮件至zlts@phei.com.cn,盗版侵权举报请发邮件至dbqq@phei.com.cn。

本书咨询联系方式:010-51260888-819,faq@phei.com.cn。

推荐序1

CNCF所提出的云原生概念在相当短的时间内得到了来自Alibaba、Google、IBM、Pivotal等公司的支持与参与,背后的核心驱动力在于通过打造“事实标准”的软件去解决云厂商对客户的锁定问题。

云原生的本质,是解决应用的弹性(resiliency)、易用性(usability)和可移植性(portability)。当这“三性”得到妥善的解决后,客户所开发的(分布式)应用可以方便、高效地同时部署于多个云厂商所提供的云服务之上,这不仅解决客户所担心的技术锁定问题,还使得应用能很好地满足法规(指要求某些影响国计民生的应用必须同时部署于多个云厂商的云上)、全球多活等严苛的要求。

在解决“三性”的道路上,Service Mesh 被视为新一代分布式应用架构的软件基础设施,并被明确地写入了云原生概念的定义中。Service Mesh 可以理解为是微服务软件架构(microservices)的进一步延伸,用于解决大规模微服务应用所面临的多语言支持、服务全局最优治理、服务(全球)发现与路由、安全保障等挑战的关键技术手段。

开源软件Istio的出现,有望成为云原生中Service Mesh的软件事实标准。Istio所提出的“数据平面”(Istio 中的 Pilot-discovery、Mixer 等组件)和“控制平面”(Envoy)通过很好的概念切分践行着软件行业解决复杂问题的终级范式——分而治之,这两个“平面”外加“运维平面”(Service Mesh中并没有定义)将能很好地助力解决云原生所致力于解决的“三性”问题。

Service Mesh 的最高境界在于让分布式应用无须关注服务(全球)发现与路由、限流、降级、熔断、安全等通用问题,但达到这一目标并非一蹴而就,这就需要同仁们在各自的岗位上共同学习、运用和成就这一技术。本书的出现能帮助读者更好地理解以 Istio 为代表的 Service Mesh技术背后的设计思路和了解阶段性的探索成果。李云 阿里巴巴中间件高级技术专家

推荐序2

近几年,随着 Kubernetes 的兴起,云原生的理念得到了大规模的推广。在整个业界,我们看到了云原生的理念正在重新塑造整个技术栈,从应用编排到服务化,再到 Serverless,等等。Linkerd 背后的公司 Bouyant 首先提出了 Service Mesh 的概念,随后 Google、IBM、Lyft 共同推出了 Istio。目前来看,它有成为 Service Mesh事实标准的趋势。因此,想要了解云原生时代下微服务架构应该如何设计和实现,学习 Istio 是一条逃不开的路径。

那么怎么学习 Istio,就成了摆在 Istio 爱好者面前的一大难题——Istio 组件繁多,功能也非常强大,要搞清楚这些组件的功能,仅凭翻阅 Istio 官方文档当然远远不够。难上加难的是,市场上讲述 Istio 的书屈指可数。

好在,周遥的这本《Service Mesh实战:用Istio软负载实现服务网格》适时问世了,它详细剖析 Istio的各个核心功能,完整弥补了这方面的资料缺失,并且介绍了国内部分互联网企业在 Service Mesh 上的实践,可谓针对这一热门技术不可多得的好书。对于想要快速了解 Istio功能,进而准备上手实践的朋友来说,这本书是有限的选择中最不会让你后悔的一个。黄挺 蚂蚁金服中间件技术专家

读者服务

轻松注册成为博文视点社区用户(www.broadview.com.cn),扫码直达本书页面。

○ 提交勘误:您对书中内容的修改意见可在 提交勘误 处提交,若被采纳,将获赠博文视点社区积分(在您购买电子书时,积分可用来抵扣相应金额)。

○ 与读者交流:在页面下方 读者评论 处留下您的疑问或观点,与其他读者一同学习交流。

页面入口:http://www.broadview.com.cn/36192序

早在2013年,我供职的阿里巴巴集团(以下简称阿里)中间件软负载团队就受运维部门之托,开始着手研究新一代的内部服务调度与治理系统。那个时候微服务概念还没有提出,但阿里在服务化方式上已经走在前列了——强壮的业务由拥有数量庞大的服务群及复杂的调用关系支撑着。运维的需求集中于希望能提供一种“更加灵活、响应更快速且更低成本”的方案来连接、控制、配置整套线上服务系统;因为在当时的LVS负载体系下,由于硬件的限制,是不可能做到快速响应的,而独立部署的LVS集群在配置与多环境下都又略显得有心无力。

当时我的领导蒋江伟(花名小邪)将这一重任交予了我并预示了 SDN(Software Defined Network,即软件定义的网络)的发展方向,我很荣幸能拥有这样的机会,当然也没有辜负他的期望。一年后,VIPServer系统诞生,第一次在阿里内部以纯软路由的形式调度各大系统间的请求,并在两年内完全主宰了内部的服务调用需求。

软路由的好处在于“软”,不与实体布线、交换机配置或硬件绑定,对于不同的流量流向什么样的地方可以任意且随时地变更,此即灵活。例如我们可以将来自 Android 客户端的流量指定到链路中拥有Test标记的服务器,这样可以实现诸如灰度发布的功能。分布式系统发布至今,系统数量空前爆炸,业务的关系与配置越来越复杂,因此对环境治理与隔离的要求也越来越高。回顾应用容器的发展,从纯硬件到硬件虚拟化、容器化再到弹性编排,无不都是走向“软件定义”这个方向,因此软负载领域也应该如此。

2017年我加入挖财,发现对较大型企业而言,中小规模企业更加饱受服务环境治理之苦,因为中小规模的企业通常没有过多精力自行研发属于自己的软负载体系,大多通过修改开源的组件来实现目的。这样的问题在于无法组成一个平台体系,虽然基本功能(如配置、服务发现)能够满足,一旦涉及多级协调功能(如链路压测、故障注入体系)的时候,便捉襟见肘了。虽然阿里早些年已经拥有这样的能力了,但想要将其直接复制到外部的企业却是一项几乎不可能完成的任务。阿里的关键技术都是定制的(如RPC服务HSF),设计所针对的场景不一定适合中小企业,即关注的点不同;所以对于中小企业而言,需要的就是一个能够连接各软负载开源产品的平面,而且这个平面应该与主流的服务编排、RPC、配置及服务发现完美兼容,并最大限度地支持链路功能扩展。

带着上述问题,我一直在思考这个产品的存在形式;而在Istio问世以后,我便相信这就是它的最佳形态。我个人看好服务网格(Service Mesh)在服务架构上的影响力,并且相信这是微服务架构的下一个阶段,因为对多数企业而言架构本身的复杂度已经开始超越业务逻辑本身,如果不加以统一管理与规划,那么只是维护成本就已经很高了。

服务网格的思想就像是分布式服务本身下沉到技术栈中,只对业务提供接口供其调用。Istio很巧妙地将其分成了“控制平面”与“数据平面”两部分,使得接口本身更加清晰。接口清晰的好处在于更加容易地定义边界与职能,例如“数据平面”部分,Istio便可以直接依托于开源Envoy 来实现,而且这并不是唯一的选择;而“控制平面”则为运维人员提供了统一的接口来操作整个链路,相较之前的零散的配置,仅这一点就可以节省不少的人力成本。[1]

2018 年,阿里顺势推出了自己的 Nacos来争夺这一领域,蚂蚁金服也公布了 SOFAMesh项目。这说明软负载仍然是大型分布式系统基础的重点,只有将环境与调用梳理清楚、高效利用起来,上层的业务及周边的扩展基础才能快速地推进。未来的分布式架构只会愈加专注,职能划分愈加精细,计算愈加弹性灵活。

虽然在本书编写过程中已经尽力反复去论证、实践每一处,但难免遗误,希望大家积极批评指正。最后我要感谢下面这些在编写本书时一直支持我的朋友们,无论是帮忙订正还是写序,感谢你们!同时本书第6章得到了蚂蚁金服团队的大力支持,特别感谢你们!当然还有在背后一直支持我的家人们,谢谢!(以下排名不分先后)

孙虹 陈霞光 蒋云鹏 吕献军 徐伟杰 李华刚 周文瑾 杨卓荦 马连志

宋越月 王伟 杨凯 蒋江伟 刘清富 黄挺 罗毅 许令波 李云[1] 这其中便包含我之前研发的部分系统,我倍感骄傲。

第1章 分布式发展史

欢迎大家来到软负载世界,这是计算机分布式计算的一个重要领域,这个世界非常有趣,因为每天都在发生新的变化。记得 2010 年刚毕业的时候,阿里的工程师们还在津津乐道于Spring、iBatis、Nginx、Thrift 等基础技术并乐此不疲;那个时候大家专注的都是一个点,没人试图将整个公司的服务集群管理与调度起来,因为在当时“环境、配置及负载”问题并没有得到很好的解决。例如配置方面:有些使用 AntX,有些使用 Maven,更有甚者是直接编写在代码里;又如负载方面:有些使用Nginx或者LVS反向代理的形式,有些则使用HSF直连的方式。在这样的混乱局面下,根本没法统一调度。

后来中间件正式成立了软负载团队,笔者也有幸运参与了 ConfigServer、Diamond、VIPServer 等经典组件的开发,见证了环境一步一步被统一与治理起来的全过程。如今 Service Mesh 概念的提出及 Istio、Linkerd 2.0、Nginmesh等一系列实践项目的出现更是让软负载如虎添翼,可以说已经达到了透明的级别,相比 2010 年的时候可谓翻天覆地。

要知道凡事都是有前因后果的,任何技术与方案都不是一蹴而就的,很多思维、思想都是在现有的基础之上进一步发展的。Service Mesh 之所以能达到今天的程度,与之前的基础是分割不开的,因此先回顾一下历史,看看软负载到底是如何由最基础的硬件服务一步步演化到服务网格(Service Mesh)的吧。

1.1 单机小型机时期

很显然计算机诞生之初只是一个工具,像汽车、电视一样,只有[1]单一的功能;不过计算机的特别之处就在于,人们能为其编写程序,不同的程序能够实现不同的功能,这就使得计算机的应用面得到了空前的发展,变得不仅仅是为少数人服务,而是普惠大众了。这个时候,就需要一种方式让更多的人能从计算机的功能中受益。当然把每个人都叫到屋里也许是个方法(如举办开放日等),但显然这太麻烦,而且受益者远远达不到普惠的程度。

好在,后来诞生了影响21世纪的互联网。1.1.1 互联网的诞生

第一个计算机网诞生于1969年,就是美军的阿帕网(ARPA),其最初仅仅是为军事目的服务的,后来一些大学由于科研原因逐步加入,慢慢就进化成今天的“因特网”(Internet)。随着计算机的普及,网上商业服务迅速崛起,网络上的服务开始由单一的信息介绍变为五花八门的服务,它们为整个世界带来了全新的面貌。[2]

2000 年初,中国的网民仅为 890 万,很多人都不知道互联网为何物,因此大多数服务业务单一且简单,采用典型的单机模型外加一个数据库就能应对绝大多数场景,所有功能都写在一个应用里并进行集中部署,如图1.1所示:图1.1 “最早的互联网服务架构”

现在看来,这简直是在开玩笑!但真的没有,这个架构对于那时的用户量来说确实足够而且简单,甚至如今知名的“淘宝网”在2003年刚刚诞生时就差不多是这个样子。

工程师们在一个大应用里添砖加瓦,需要发布的时候就集中打包,如果遭遇错误就全部回滚。好在那个时候各部分功能都还算简单,在依赖组里吼一声,给个接口名,在系统内部引用再调用一下也就解决了。同时那个时期还有很多经典的设备,如 IBM的小型机(如 Power 系列),或者 EMC的高端存储(如Symmetrix系列)等,都是单机时代的典型代表,它们追求的都是单机服务能力,那个时候还没有分布式一说。1.1.2 复杂应用拆分[3]

不过到了2018年,中国网民的数量达到了惊人的 7.72 亿(上涨了近100倍),而且随着应用的日益复杂化与多样化,开发者们对系统的“容灾、伸缩及业务响应能力”有了更高的要求。

暂且不说用户增长的影响因素,单纯从服务的稳定性与功能上来讲,单机架构就有很大的问题,因为如果“服务器”和“数据库”中的任一个出现故障,整个系统就会崩溃,或者说若某个板块的功能需要更新(例如“新闻网页”),那么整个系统便需要重新发布。显然,对于业务迅速发展的万物互联时代,这两点就足以致命。

因此,工程师们开始思考,如何在保障可用性的同时快速响应业务变化。他们想到了将一个应用拆分成多个应用的方法,也就是将上面的“大统一”拆分成多个子应用,“新闻页面”应用、“聊天室”应用、“论坛”应用等,这种方式被称为垂直拆分。它们各自有整套的硬件体系作为支撑,于是就变成了图1.2的样子。1.1.3 遭遇性能问题

应用垂直拆分确实解决了应用开发中发布的问题,现在每个应用都可以独立设计、开发及部署了,工程师们非常兴奋,干劲十足,新功能不断上线。不过随着用户数量指数级的增长与摩尔定律的限制,单机计算能力完全跟不上业务的发展,这个时候工程师们发现,买再高端的计算存储设备也是杯水车薪,不能从根本上解决问题;而且,高端的计算设备往往非常昂贵,例如 IBM经典的 Power系列,当时的售价就高达十几万美元,这样的开销对于小型企业简直是天方夜谭。

因此这个时候,工程师们就需要一种廉价同时拥有高性能的解决方案。什么?廉价又高性能,确定这不是在做白日梦?如果按照之前单机的思路当然是不可能的,但我们可以换个思路来解决这个问题。图1.2 “业务垂直分拆后的部署架构”

1.2 集群化时期

为了满足日益增长的业务需求,工程师们不断上线性能更加强悍的服务器。直到有一天,老板实在招架不住高昂的成本了。这里的成本不仅指购买机器的成本,更多的是这些机器的维护成本——由于高端机器的维护都需要受过专业培训的人员,普通工程师难以胜任;另一方面,受摩尔定律的限制,单核 CPU 的发展也跑不过业务的发展。

这个时候工程师们就想起了“三个臭皮匠,顶个诸葛亮”的老话(当然是开玩笑)。1.2.1 从高端设备到普通PC

虽然 IBM 小型机的价格非常昂贵,但那个时代有种硬件相对来说要便宜许多,而且也拥有与小型机一样的计算功能(注意是功能而不是能力),那就是 Intel X86 普通 PC,即常见的“电脑”,虽然单从计算能力上来讲,普通 PC 相比 IBM 小型机简直相差万里,但是它们的计算架构却是一致的。例如小型机可能动辄就是 128GB 的内存,普通 PC 最多也就 8GB,因此单从计算能力上,普通 PC 在服务领域是没有任何使用场景的;不过随着一种被称为“负载均衡(Load Balance)”设备的出现(例如经典的 F5Networks BIG 系列,如图1.3所示),工程师们得以汇集微小的力量于一体。图1.3 “经典的F5 BIG-IP硬件负载均衡设备”1.2.2 硬件负载均衡设备

负载均衡设备虽然五花八门,但其工作的基本原理大同小异,都是通过网关的形式将流量反向代理并转发给下游的,下游是多个功能一致的 X86 服务器,以此组成一个集群。负载均衡设备往往会对外暴露一个统一的接口,让外界用户感觉是在向同一个主机发起请求,然而实际上,后端的服务器已经集群化了。集群化的好处是可以随时水平扩展,因为每台机器的功能都是一样的,也就是说如果需要将原来的压力缩小一半,只需要将机器的数量扩充一倍即可。“负载均衡”设备一般还会支持健康检测,当有新的服务器加入时,可以动态将流量分配给它们;同时在某台服务器出现故障时,又能够及时将其从流量下发列表中摘除,避免无效的流量转发。

同时负载均衡设备还是服务的入口与出口门户,即网关。利用这个优势,它们可以对流量进行清洗与预处理工作,例如安全流量打标与防 DDos 攻击等。

负载均衡使得 PC 能够将微小的力量结合起来,形成一个集群,并第一次引入了水平扩展的概念,实现了动态扩缩,相对于之前笨重的单机部署,可以说是质的突破。1.2.3 资源配置问题

之前小型机无论多么强大,运算能力都受硬件限制,而硬件的采购、部署周期又非常长,因此为了保险,早先很多公司的运维都会预留好机器资源以供业务发展不时之需。

这样做的问题在于,会出现大量的闲置硬件资源。比如,企业预估业务在年底能够达到80GB 内存的需求量,而年初采购时业务实际只有 20GB 的需求,根据上面的策略,企业仍然会将 80GB 内存的机器买回调试好以期待其用武之地。那么,也就是说 60GB 的内存很多时候就真的是在空转了。如果业务发展顺利,那还好,虽然等待时间有些长,但终归还是用上了,但是出现不及所期那就惨了,因为硬件在使用后厂商一般是不允许退货的,也就是说不能以这60GB多余内存用不上为由,希望厂商回收。

而且,随着业务的多样化,特别是电商类场景,经常需要组织一些大的促销,业务压力往往会急剧上升,单机即便性能高,也有极限,在达到瓶颈后很难有所作为。1.2.4 积少成多的优势

使用集群则不一样,可以施展化整为零的功夫。虽然一台普通 PC 内存一般为 8GB(实际上 2010 年的时候一般只有 2GB 左右),但工程师可以用 10 台PC 组合成一个服务集群,形成 80GB 的服务能力。这样在年初的时候,只需采购 3 台回来组成集群就够用了,到了年底的时候,可以再采购剩下的部分或者业务将出现瓶颈的时候再采购,要知道采购部署一台普通PC 可比 IBM 之类的小型机轻松多了。

当初小型机甚至大型机之所以有市场,是因为那个时候的普通 PC 硬件及软件技术没有达到企业高稳定性、高容错性的需求,也就是说普通 PC 可能没用几天就会不是这里坏就是那里有故障,IBM 等优秀的公司很好地帮助企业渡过了那个难关,也确实为计算机历史做出了贡献。不过随着 X86 及 Linux 开源生态的发展,普通 PC 变得愈加稳定,再加上 HP、DELL 等一系列优秀的服务器生产厂商的加入,普通 PC 作为服务器已经不再是什么新鲜事了(当然这里的普通 PC 还是不能与家用的画等号的,一些细小的部分是针对企业应用专门优化的,例如双CPU 双通道内存主板)。1.2.5 集群化架构

回到之前谈论的集群部署架构,通过普通PC的堆砌,工程师们成功将架构进化成了如图1.4所示的样子。

现在性能问题是解决了,如果业务规模再上升,就可以通过单纯的堆砌机器来解决。集群思想不仅适合服务器,后端的数据库也适用,[4]在这样的思想上产生了“一主一备”“一主多备”等经典的部署结[5]构,并出现了分库分表中间件。图1.4 “集群化后的部署架构”1.2.6 软件负载设备

早先时候的负载均衡设备都是基于硬件的,后来工程师们为了节省成本,编写软件使用普通 PC 开发了廉价的负载均衡设备,例如 [6]LVS(Linux Virtual Server)这样的产品,与硬件的功能一致,只不过使用了软件的形式来工作,这些产品的诞生标志着负载正式进入“软负载”时代。

但渐渐地,工程师们发现,很多功能都被重复建设了,例如其中的“聊天室”与“论坛”都会涉及用户信息功能(例如登录、用户基本信息采集等);另外,由于应用分开部署,都需各自设计一套,从前端的信息录入到后端的存储结构。图1.4只有4 个系统,问题也许还不太明显;但今天,一个复杂的系统包含成百上千个应用是常见的事,这样的功能重复显然对企业来说是严重的资源浪费。

1.3 服务化时期

1.3.1 应用到服务

重复建设在软件工程思想中向来就是不可取的,工程师们设想将共同的功能组件抽象出来,形成独立的“应用”,不过这里的关键问题就是这些“应用”没有直观上的入口,因此用传统的思想来定义并不妥。为此工程师们想出了“服务(Service)”一词来描述这种功能性的组件,它们为应用提供通用功能性的支撑,“服务”于具体应用。

如今“服务”这个词在软件工程中已经泛化,可以说,凡是向其他组件提供“支撑”功能的系统都可以称为服务,甚至还出现“软件即服务”(SaaS)这样的概念。在这种概念下,软件不再是整体打包一次性卖给消费者,而是消费者在使用时按需获取,而且服务还会不定期升级,消费者无须感知,并可以按使用时长或者资源的消耗率来计算费用。“服务”思想其实就是把其他应用当成了消费者,为其提供特定功能。上述应用架构中的“登录、采集用户基本信息”等功能可以抽象成一个名为“用户中心”的服务组件。以此类推,还可以继续抽象出“消息中心”“索引搜索”“文件存储”“缓存系统”等通用服务组件,总的原则就是尽量提取公共的部分以避免重复的开发工作。

之后,功能的开发也即服务的开发了。1.3.2 远程调用

服务拆分后,就像天上的繁星一样分散到不同网络的各角落了,那么现在的问题是如何互相访问呢?前面说过了,服务与应用不同,没有可视化的页面可以访问,而且调用者是计算机程序而不是人类用户,工程师们需要一个程序之间的通信协议,就好像下面的对话一样明了方便。“我需要用户A的记录,请给我它的结构及数据”“好,这是A的记录的结果及数据,请拿好”“远程过程调用(Remote Procedure Call,简称 RPC)”协议应运而生,其作用就是让应用(服务)之间的程序调用变得像本地一样简单,这种技术完全屏蔽了各种网络拓扑的复杂性,只要知道对方的“地址”就可以发起调用。

RPC 在 Java 生态中,最早出现在 1.1 版本中的 RMI(Remote Method Invocation)中。Oracle 后来又提出的 EJB 那一套,基于 JAX-RPC 接口——JAX-RPC 基于 SOAP(简单对象访问协议),调用地址都是由“类目服务器(Name Server)”来注册管理的。

在这种方案下,访问某个远程服务需通过以下类似代码:

可以看到上述代码中有一个 URI,这就是该服务的地址,消费端通过它可以发起访问以获得数据。1.3.3 虚拟IP地址

可不要认为 RPC 就只是调用。这里有个前提,就是服务端得把自己的地址注册上去,但是在集群环境下有多台机器,如何处理呢?这些地址 URI 又怎么告诉消费方呢?另外,当服务不可用时,谁又去把这些注册信息拿掉呢?

这里工程师们想到的解决方案就是前面提到的负载均衡设备概念中的“虚拟 IP 地址(简称 VIP)”,只需要在注册的时候填写 VIP,那么在调用的时候,请求经过负载均衡设备,其就会自动地将流量均分到下属已经注册的机器中,并且在应用上下线的时候,会自动对下发的机器列表进行调整。

在增加了 RPC 功能后,工程师们终于可以将公共的服务单独部署,现在整个架构如图1.5所示。图1.5 “服务化后的部署架构”1.3.4 复杂的调用关系

历史的车轮继续向前,业务量再一次发生了巨大的增长,请求不断涌进来,新的应用不断增加,这使得公共服务也变得越来越多,整个调用网由最开始的十几条线变成成百上千条甚至上万条,甚至到了后期,已经没人能弄清楚到底有多少条调用关系了。

图1.6 就是某企业的全局调用关系,可以看到,这里面的调用链错综复杂。图1.6 “某公司的服务调用关系”1.3.5 服务治理

复杂的服务订阅关系必须要很好地维护起来,否则在出现问题的时候可能完全不知从何入手,所以这个时候,一种叫“服务治理(Service Governance)”的软负载产品出现了。它的基础工作跟注册中心一样是维护一个订阅关系,不过在订阅关系的数据之上,还提供了更多高级功能,比如:根据负载情况选择最优服务节点、多版本链[7]路支持、订阅关系鉴权限流降级以及灰度发布等。

经典的 RPC 框架 Dubbo 就有一个专门的服务治理子系统,其底层采用 ZooKeeper 作为数据存储,如今经常提到的 Spring Cloud 则是采用名为 Eureka 的自研产品。

Dubbo的“服务治理”采用的是ZooKeeper,由于其自身数据结构的设计,其服务关系存储采用的是树状结构,如图1.7所示:图1.7 “Dubbo在ZooKeeper中的数据存储结构”

这种存储结构的优点在于可以很容易地监听数据变化,例如需要监听“服务A”对应的“提供者”变化情况时,只需要将监听点挂载到服务A的“提供者”父节点即可。同理,如果需要同时监听“提供者”与“消费者”,只需要将监听挂载到“服务”节点即可。然而不足也是很明显的,例如需要进行关联查询时,树状的层次结构就不那么方便了。比如需要查询机器 M1 订阅的所有服务,这种情况下只能逐一遍历,其时间复杂度为 O(n),其中 n 为服务数量,并不高[8]效,再加上 ZooKeeper 强一致的设计,从性能与功能上来讲,我个人认为都不适合作为“服务发现”来使用。

现今,工程师们普遍倾向使用 etcd 来实现“注册中心”,其特点是采用 KV 存储,对于结构性查询,更加轻量、易运维,优势更佳。

订阅关系可不仅在 RPC 中,任何链路,只要存在服务一说,都会涉及这个概念,比如著名的开源消息框架 RocketMQ,也会使用一个目录服务器(官方名称是 nameserver)来维护Topic 与 Broker 之间的映射关系。

服务治理维护的数据,从根本上说就是“提供者”与“消费者”之前的映射关系,例如有3台机器在提供服务 A,则标记为 A={M,M,M},同时有 2 个消费者在调用 A 的服务,则记provider123为 A={N,N},可以看见这两条数据均为矢量数据,因此如subscriber12何较好地结构化存储,是链路关系维护的关键。

当然可以尝试将其存储在数据库中,但这里的问题是,订阅关系通常是实时变化的,而且需要通知功能。比如提供A服务的M这台机1器宕机,消费者A需要监听到这种变化,否则会将请求路由subscriber到一个已经宕机或者下线的服务上,导致错误的请求。更复杂的情况是,可能一个关系变化会连锁式地影响到其他链路。

例如 B 服务其实就是 A 服务的一个消费者 N ,而 B 服务本身3又有消费者,那么当 M出现故障时,A 变成 {M,M},这时 1provider23B 的流量入口从之前的三台下降到了两台,B 服务的链路能力是有下降的,即整条链路的吞吐量都受到了影响。如何及时、直观地反映问题,到如今也是个棘手的问题,这点更是弹性调度不可或缺的基础。

可以说软负载中的“服务治理”发展到今天已经远不只“服务注册”那么简单了。1.3.6 旁路负载

由于“服务治理”系统的存在,工程师们再也不用为应用之间复杂的调用关系而担惊受怕了,分布式得以空前发展。

因为“服务治理”通常都提供健康检测功能,已经能够很好地维护服务对应的机器列表,所以之前讲到的 VIP(虚拟 IP 地址)便变得不那么必需了。这个时候工程师们想出了一种“旁路负载”(亦称透明负载)的软负载架构,它的特点是并不直接通过代理流量来分发负载流量,而是在 RPC 客户端中直接埋入负载及其他链路逻辑,这样就省下了网关代理这层,但是由于对外需要统一暴露接口,因此对外的网关仍然需要保留。

当然,对外的网关已经不是简单的流量负载均衡,像“接口版本管理、攻击防御、请求重定向”等功能也被加入了,这个时候它有了一个更贴切的名字,叫“API 网关”。像读者熟知的 Spring Cloud 框架,其 Zuul 组件充当的便是“API 网关”的角色。

最终系统架构便变成了图1.8的样子:图1.8 “采取旁路负载后的架构”

如此一来,系统内部的访问阻碍已经减少到很少了,同时随着 [9]Docker 容器化及 DevOps思想的迅速崛起,服务的粒度可以拆分得比以前更细,让需求开发更加独立、互不影响,这就是之后出现的微服务一说。

1.4 微服务时期

1.4.1 服务细化

微服务是2012由Martin Fowler提出的概念,并没有严格的定义。从本质上来说,分布式经过前一轮的服务化后,应用本身臃肿复杂的问题已经得到了很好的解决。不过微服务则希望将其更进一阶。这里的重点就是“微”,即一个服务只负载一个独立的功能。此时,传统的“用户中心”服务,对于“微服务”来说,根据业务需要可能就需要再次拆分,例如针对电商场景,可能就需要拆分成“买家服务”“卖家服务”“商家服务”等。

至于到底需要拆分到多细,这里的原则便是,任何一个需求不会因发布或者维护而影响到不相关的服务,一切可以做到独立部署运维。当然,甚至可以拆分到一个独立的功能、一个服务,肯定就不会[10]相互影响,这也正是 Serverless 思想所提倡的。不过 Serverless 尚需要较多的基础服务支撑,而且还没有被主流公司接受,因此服务的拆分粒度,现在仍然是一个没有明确界限的事。1.4.2 架构轻量化“微服务”所强调的不只是服务划分粒度上的“微”,同时对整个架构也有更高层次的要求。例如“微服务”希望远程调用协议是非常轻量级的,它不提倡使用像 Dubbo 这样的强语义协议,因为每种语言都需要一个针对性的客户端,而且客户端逻辑还比较复杂,甚至还支持编写Groovy 语言来自定义扩展。

广为大众所接受的Spring Cloud框架是微服务的典型代表。相对于传统分布式服务架构,Spring Cloud使用HTTP作为RPC 远程调用协议,配合上 Netflix 贡献的 Eureka 与 API 网关Zuul,其能做到细分内部服务的同时对外暴露统一的接口,让外部终端对系统内部分布式架构无感知。此外,Spring Cloud 的 Config 组件还将配置与上述各框架结合起来,让每个服务都可以非常简单地接入并配置系统。

综上所述,在我看来,“微服务”所强调的轻,其实就是反映工程师们普遍不希望分布式相关架构逻辑侵入业务系统的事实。在传统的分布式服务架构中,一个服务(应用)通常要非常多的配置才能正常工作,例如 Dubbo 需要填入配置中心地址、配置 Service 接口 XML 文件等,并且要求对方也接入 Dubbo 客户端才行,而 Spring Cloud 则只需要通过几个简单的注解即可完成对服务调用的声明,因为是基于HTTP的,即便是不同语言,也可以很好地支持。

纵观整个分布式发展史,微服务时期可以说是一个发展的分水岭,因为此时工程师们真正开始注意到架构本身带来的复杂性。在此之前,分布式都是往做多做细方向发展,例如之前“集群化”“服务化”“服务治理化”等一系列过程,都是一种架构扩展演进。而微服务在细化的同时,首次提出了“微”,即轻量级的概念,在此之后,分布式架构便进入了一个架构收缩的过程,因为其本身已经太复杂了,工程师仅是理解业务估计都需要好几天,因此需要让他们尽量少地去感知架构的存在,甚至做到完全无感知。

要知道,所有这些对于加班如家常便饭一般的工程师来说,那是一件非常幸福的事。

1.5 服务网格(Service Mesh)新时期

1.5.1 多语言的困难

分布式关系日益复杂还不仅体现在调用关系上,随着多语言、前后端分离等思想的发展,在架构中呈现编程语言多元化的趋势,例如 NodeJS、Golang(近期非常热的配置中心 etcd 就是用其编写的)、Scala(大名鼎鼎的 Kafka 就是用其编写的)等。

本来仅维护调用关系就已经让工程师们焦头烂额了,现在还需要对多语言进行支持(熟练掌握一门语言及其生态还是需要一些时间的),并且不同的语言还有不同的编程风格,所以多语言支持真的不容易。再者,由于多语言客户需要侵入上层业务代码,开发人员就不得不在学习(至少了解)整个服务架构后,才能较正确地做出是否能够接入那些客户端的判断。1.5.2 指数级增加的系统复杂度

业务需求不断升级会导致系统复杂度呈指数级增长,工程师们经常遇到这样的现象:同一段时间内,一个产品可能有好几个需求在并行开发,而开发环境却有限;某些应用包含敏感数据,并不希望将接口完全公开;隔三岔五的产品活动,对系统稳定性有很高的要求,测试希望能将压测常态化,最好还不影响线上应用。整体系统复杂度并不像最初预估的那样呈线性增长,其往往呈指数级增长。这一点,从图1.9中每年双十一的销售额就可以看出来。

所以这时“多版本、多权限、动态限流降级”等一系列针对链路的高级功能需求被陆续提了出来。为了满足上述要求,工程师们不得不编写更多的系统,有针对“分布式锁”的,有针对“分布式鉴权”的,有针对“多版本”的,等等。这使得分布式系统本身愈加复杂与笨重。事实上,仅搭建与维护一套分布式架构至少都需要一个专业的团队支持(通常这个团队叫“平台架构”或者“中间件”团队),每个产品至少需要半个专业的工程师来维护,理解这些概念对于非专业的业务工程师来说负担可就更重了。表1.9 “双十一总销售额与系统复杂度关系”“微服务”虽然强调轻量化框架,但仍然无法避免系统愈加繁多的问题,服务细化得越厉害,只能让逻辑越轻量并解耦;但服务分得越细,数量就越多,维护成本自然就越高,这并不能解决维护成本问题。1.5.3 Linkerd诞生

到了 2015 年,一家名为 Buoyant的公司向外界公布了一种架构空前的产品,其为每个服务分配了一个专用的称为“边车网关(Sidecar)”的系统,并将其与“服务发现”的公共服务相连,服务地址及控制信息便通过“服务治理系统”统一下发,其系统概念如图1.10所示:图1.10 “Linkerd系统基本架构”

如此一来,随着接入应用的添加,网关之间便形成了一个特殊的大网(如图 1.11 所示),其承载着链路请求的路由、治理及其他任何与链路相关的工作。由于网关独立于业务应用而存在,因此其与业务逻辑是完全解耦的,并且开发人员是无感知的。Linkerd 巧妙地向上层应用统一屏蔽了分布式架构,让业务开发变得更简单、纯粹了。图1.11 “随着应用的添加,Linkerd网关之间形成的大网”

可是Linkerd 在 2015 年推出后并没有受到业界的关注,主要原因是 Linkerd 为每个服务部署一个网关的想法在传统运维体系中实在是太难实现了——部署、维护工作几乎多了一倍。1.5.4 第一代服务网格架构

但是到了2017年,随着“微服务”与“容器化”技术的迅速发展,以上问题就非常简单了,只需要将网关程序打包到基础镜像[11](Image)即可解决。随后 Linkerd 的想法迅速走红,受到越来越多工程师的青睐。不久后 William Morgan(Buoyant co-founder and CEO)在 Linkerd 官方博客上撰写了一篇名为 What’s a service mesh?And why do I need one 的文章,将 Linkerd 的构想定义为“服务网格(Service Mesh)”,并做了比较严谨的定义。

Service Mesh 是一个“基础设施”层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,Service Mesh 保证请求可以在这些“拓扑”中“可靠”地穿梭。在实际应用当中,Service Mesh 通常是由一系列轻量级的“网络代理”组成的,它们与应用程序部署在一起,但应用程序“不需要知道”它们的存在。

这里有几个关键点,要强调一下。

○ 基础设施:Service Mesh 是未来云计算中不可或缺的基础框架,就像 TPC/IP 协议栈一样,虽然开发人员不需要感知,但其中服务路由与治理的基础,为云计算提供服务通道与保障。

○ 拓扑:Service Mesh 所提供的网关组成一个庞大的网格,由此网格统一为应用提供服务,其是对物理网的一层分布式抽象。

○ 可靠:由于其组成的网格为上层服务提供一层统一的代理,其作为基础设施需要高度可靠,否则上层业务会非常头痛。

○ 网络代理:其是对所有服务设计的一层透明代理,可以跨言语。

○ 不需要知道:其是一层服务栈,拥有对上层支撑的全套功能且对业务无侵入,在层次上定义了其存在位置。

从上可以看出,第一代架构是从数据逻辑层面上解决了微服务关系混乱的问题,但它并没有实现控制。Sidecar 将各服务连接了起来,并做到请求接管,但是没有一个有效的系统或者设计来管理这些 Sidecar 的配置。1.5.5 第二代服务网格架构[12]

这之后 Linkerd 被 Google 收编到了 CNCF 基金中,现在已经作为一个开源软件在发展,但是由于其是使用 Scala 编写的,在性能上表现不佳(Scala 需要 JVM 作为运行环境,通常在启动的时候就至少占 200MB 内存),再加上后来 Google 为了推进 Kubernetes 在云上的发展,自己另起炉灶发布了Istio,使用的网关是 Envoy,Linkerd 可以说前途昏暗。

也许是 Buoyant 自己也感觉到把 Linkerd 交给社区之后使其思考及发展都受到了严格的限制(在社区由于需要公共参与,每个决定都需要经过较长的时间),2017年又用 Rust 研发了Conduit。Conduit号称是一个非常轻量级的 Service Mesh 方案,不过由于 Rust 是一种非常小众的语言,再加上这个时候 Google 的 Istio 势如破竹般地发展,Conduit 现在在业界的接受度也是非常低的,更不要谈大规模实际生产了。

第二代服务网格典型的特点便是同时拥有了数据接管与集中控制能力,Google 分别将两个能力对应的系统定义为“数据平面(Data Plane)”及“控制平面(Control Plane)”。1.5.6 生产应用情况

由于 Istio 是 Google 巨人主导的,很有说服力,所以各大厂商愿意跟进研究并投入试用,本书中所讲解的 Service Mesh 大部分内容也都基于 Istio。其实除了国外研发的开源产品,国内很多团队也已经在着手研究了,这些团队主要分为四类体系。

○ 以蚂蚁金服为首的开源系:蚂蚁金服自研的 SOFA (Scalable Open Financial Architecture)Mesh 在开始的时候走的就是开源路线,他们参考了 Istio 及 Envoy 的设计思想,重新实现了自己的 Service Mesh 系统,旁路网关(Sidecar)基于 Go 语言,该系统的前身是已经开源的 SOFA RPC 框架。蚂蚁金服于 2018 年 7 月正式将其开源,正式的可以用于生产的框架可能还需要一些时间。

○ 以华为为代表的自研系:华为可能在 Service Mesh 概念出来前就已经有类似的想法了,只是没有抽取出一个公共的概念。无论是华为早期的 HSA 还是之后出现的 CSE Mesher,都是对 Service Mesh 的探索。CSE Mesher 的整个架构都是基于华为自身微服务架构经验研发的,其 Sidecar 也是用 Go 语言编写的。如其官方文档所述,其资源占用非常小,常规状态下仅为 30MB。

○ 以腾讯为代表的拿来主义系:腾讯的 Tencent Service Mesh对开源的产品(如 Istio)进行定制,强化吸收后再加入自身特殊的业务逻辑。腾讯选择的Sidecar是Envoy,使用 C++编写,比较符合腾讯的技术栈。其公开的技术并不多,仍然以内部小范围使用为主。

○ 以 UCloud 为代表的适配系:主要也是依赖开源方案,但不是完全将其产品引入,只是对其中几个关键部分添加适配器,以适应企业现有产品,以最小的变更成本引入Service Mesh 体系。

能够看出,服务网格概念虽然火,但并不是像 Spring Cloud 及 Dubbo 那样经过实战考验的、成熟的框架——企业要想拥抱服务网格,通常情况下只能自行研发或改造。虽然 Google 已经在试图通过 Istio 来为业界设立一个通用标准,但从现状来看,还有比较长远的路要走。

可以说现在 Istio 已经独领风骚,在服务网格这个领域确立了坚实的根基,特别是其在2018年8月发布 1.0 正式版本之后,基本上就已成为唯一一个可以实际用于生产环境的开源框架。

服务网格是一个全新的概念,各大公司在争相研究与实践,我相信服务网格将来必然是云服务的重要根基之一。

1.6 本章小结

回顾计算机发展历史,能够发现分布式的发展跟计算机网络发展非常类似。它们都经过节点由少到多,再由多成网的过程。

TCP/IP 协议诞生是解决计算机之间相连的问题,虽然是几十年前的产物,但到今天仍然是计算机网络传输中的基础,而且在大部分情况下都不需要感知到它的存在。服务治理也面临类似的问题:从最开始的单机到集群再到微服务时代,硬件成本越来越低,服务数量呈指数级增长,使得调用关系越来越复杂,这时工程师们就需要一种方式来有效管理这些服务及调用关系;历史总是惊人的相似,只是现在我们面临的不再是如何有效地将计算机连接起来,而是如何将服务透明地连接起来而已。

为了让上层业务开发更加轻松,工程师们需要想出一个方案,将底层的细节更好地隐藏起来,无感知地变迁下层基础服务——这个方案就是 Istio。经过了“集群化”“反向代理”及“旁路负载”前三代的进化,软负载迎来了第四代“服务网格”架构,其统一透明的架构为服务治理提供了全面的支撑,并具备高度可扩展性。

接下来的几章,笔者将使用目前使用面最广的 Istio为大家详细讲解服务网格的实现原理,同时为大家剖析 Istio 的架构设计。[1] 现代计算机建立在图灵计算模型之上,这种模型描述了“一个输入、一个计算、一个状态及一个输出”,程序便是在计算与状态之间的转换指令,因此只要指令够丰富,就可以产生变化无穷的结果。[2] 数据来源:《中国互联网络发展状况统计报告(2000/1)》。[3] 数据来源:2018年第41次《中国互联网络发展状况统计报告》。[4] 可以使得当主库出现问题的时候业务整体的容错能力有了很大程度的提升。[5] 分库分表即按照一定的主键规则,将数据散列到不同的表或者库中以实现数据库的水平扩展,像开源的Cobar,就是典型的分库分表工具。[6] LVS是由章文嵩研发的基于普通X86型PC的软负载均衡产品,其代码已经开源。[7] 多版本链路指同一个服务可以有多个版本存在,不同版本之间调用不互串,可以共存,而版本的选择通常是根据请求中附带的版本信息决定的。[8] ZooKeeper 采用的一致性协议 ZAB 源于 Paxos,其要求多数写入成功后,写入请求才算成功,并且只能由主节点写入。[9] DevOps 讲求的是开发运维一体化,通过辅助工具及自动化工程,简化运维上的开销,让开发人员都有能力安全地运维自己开发的应用。[10] 这里并不是说一个服务、进程便是 Serverless,Serverless 是一个新型互联网架构,应用逻辑并非全部在服务端实现,而是采用FAAS(Function as a Service)架构,通过功能组合来实现应用程序逻辑。[11] 镜像是容器技术(例如 Docker)里的概念,开发者将程序运行环境与代码一起打包成一个文件,称为“镜像(Image)”,在运行时容器会根据镜像里的内容为程序创建一个完全独立的沙箱环境。[12] Cloud Native Computing Foundation(CNCF):它是由 Google 发起的类似于 Apache 开源基金会的一个开源软件基金组件,其主要发展及扶持云计算相关的开源工具及框架。

第2章 Service Mesh:以Istio为例

第1章通过对软负载的历史回顾,道出了服务网格(Service Mesh)是微服务治理困局下的必然结果。虽然服务网格是一个新兴的概念,但其相关的话题却非常活跃,而且像 Google、腾讯、蚂蚁金服等大公司已经在跟进研究了,其中最出色的当属 Google 主导的 Istio。

本章首先会向读者介绍 Istio 的几个概念,然后再从零开始向 Istio 环境部署一个最基本的HelloWorld 服务群,以展示服务网格的魅力。

2.1 Istio的设计理念

Istio 首先是服务网格(Service Mesh)的一个工程实践,说到服务网格首先想到的就是Sidecar,它独立存在于业务逻辑,这使得跨语言调用变简单——上层业务方完全无须感知复杂的分布式逻辑。同时由于 Sidecar 与业务部署在同一个资源单元上(如虚拟机或者容器),方便地实现了链路流量路由及安全控制。Istio的设计理念核心就是将所有链路管理都下沉至协议级别。这样做不仅能对业务方透明,还能将链路管理统一收拢在平台,可谓一举多得。

笔者认为,任何一个优秀的产品在开始设计时都需要有一个初心,即我的产品解决什么问题,在什么样的场景下发挥作用,其适用的用户群体是什么等,这样之后的功能才能紧密围绕初心而不断强化,否则就会慢慢地偏离自己预设的路线和起初的目标,功能虽然越来越多,优势却越来越不明显。

因此要理解 Istio 的设计理念,就得从其诞生的大环境说起,以了解在当时的场景下遇到的问题是什么,设计团队想解决的问题是哪些,这样就能慢慢理清楚了。2.1.1 Istio的诞生背景

Istio 是 Google 于 2017 年 5 月推出的服务网格(Service Mesh)产品,已于 2018 年 8月推出 1.0 正式版本。Istio 诞生之初,即 2017 年,正值微服务编排 Kubernetes 发展的繁盛时期,各大技术论坛都在讨论 Docker 及微服务弹性伸缩,微服务理念得到了空前的发展。微服务本身并不强调语言架构上的统一(使用的 RPC 都是基于 HTTP 的,具有很强的跨语言特性)。开发者可以根据需要选择(尽量一个进程一个服务),唯一需要注意的就是,在微服务中,任何一个服务都只具备单一的功能,因此会产生很多的独立服务部署。

那么随之而来的问题便是:这么多的微服务,这么多的调用及系统流量,如何才能有效地管理起来呢?而且同时还需要支持不同的语言及不同的部署平台。

经过综合考虑,Istio 的设计者们决定它应该是一个提供连接管理、安全控制、负载限流的统一微服务平台。Istio 不仅提供了服务之间的流量控制、访问控制策略,还集成了各种链路服务(例如链路跟踪 Zipkin)及相关的扩展接口,这一切都是无须上层业务感知的。

总之,Istio 能给用户带来:

○ 针对 HTTP、gRPC、WebSocket 及 TCP 等协议的自动负载均衡。

○ 精细的请求流量控制,支持众多路由、重试及容灾层面上的规则,支持故障模拟。

○ 模块化插件扩展支持,可通过 API 进行访问、频率限制及配额方面的控制。

○ 全自动化的请求遥测(Telemetry)、日志分析及全链路跟踪系统,所有请求都在掌控之内。

○ 全链路安全访问控制与身份认证。[1]

Istio 的核心意义在于:适配多种 Pass平台,把调用链路相关工作从业务逻辑中彻底剥离出来。形成“数据平面”,再通过添加“控制平面”进行统一控制,把整个链路负载工作都下沉到了PaaS基础技术栈上层,从此业务开发工程师不再需要关心内部实现,就像使用云服务一样简单。简单来说,Istio提供了服务网络(Service Mesh)基础环境。

在Istio的控制平面中,管理员可以通过统一的配置下发给各节点,能非常轻松地对全局进行操控,这些功能以前也许需要几个甚至十几个系统,如今都被集成到了一起,1~2 个工程师即可轻松维护,降低了整体运维成本。

因此,Istio的核心便是“数据平面”与“控制平面”两部分,外加“数据平面”衍生出的“安全控制”。接下来笔者便为大家一一介绍。2.1.2 控制一切的两个平面

首先来看看 Istio 的全局模块,如图2.1所示。图2.1 “Istio官方给出的全局架构图”

从图 2.1“Istio 官方给出的全局架构图”可以看出,所有的服务都加装了一个代理,系统间通信都通过这个代理来进行;如此一来,业务都不需要费力去搞清楚如何到达其他服务了,它们就像在一个应用里一样,不必去感受复杂的分布式拓扑。

对于这样功能奇特的代理网关,Istio 将之称为 Sidecar,直译过来就是“跨斗”。边斗源于一种特殊的摩托车,这种车的最大特点是侧边挂载有一个独轮小车,与主体可以是一体式的,也可以是挂载式的,如图2.2所示:图2.2 “跨斗摩托车”

在 Istio 系统中,Sidecar 只是一个概念,它具体是由 Envoy 这个

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载