2017 年 4 月 25 日 Buoyant 公司的 CEO William Morgan 给 Service Mesh 下了个完整的定义,简言之,“Service Mesh 是一个专用的基础设施层,用于使服务到服务的通信安全、快速和可靠 ... ...”,其实更确切地说 Service Mesh 应该诞生于 2016 年,因为回看很多 Service Mesh 方案早在 2016 年就已经开始摸索前行。随后的几年如雨后春笋般出现了很多实现,逐渐形成了其基本事实标准:负责服务间通信的数据面,以及控制整体流量在体系内流转的控制面。Service Mesh 可谓是当下微服务领域最火的模式。被认为是下一代的微服务。甚至 2018 年被称为 Service Mesh 元年。
本文,我试图从自己实践 Service Mesh 过程中的一些感悟出发去探寻 Service Mesh 的本质,希望能给正在关注 Service Mesh 或者计划实践、落地 Service Mesh 的你带来一些我的理解,毕竟大家已经观望 2 年多,也该考虑落地了。
为什么要讨论“Service Mesh 到底是什么?”这样一个话题,因为我发现一个有趣的现象,现在大家谈论 Service Mesh 时,几乎就把它与 Istio 画了等号,尤其是越往后关注这个技术方向的人这种情况越明显。从另一个角度来看,这也算一种技术垄断,大公司背书的 Istio 经过这两年的发展与其专业的开源运营,几乎掩盖了所有其它方案的声音,让新进的开发者误以为 Service Mesh 就是 Istio。这会带来一个现实问题: Istio 并不一定适应所有的场景。我觉得 Mesh 社区有位同学说的一句话特别有道理“垄断使得包括其在内的竞品并未通过足够长时间的竞争达到相对的成熟,就过早形成了某种心理意义上的垄断预期”。导致当下可能很多团队可能在自己的场景强推 Istio,忽视了自己真正的痛点或者臆想自己有 Istio 预设那样的痛点,如此复杂的 Istio 体系如果方向选不对,折腾到最后可能吃力不讨好。
图一: ServiceMesh != istio
那么 Service Mesh 究竟是什么?
Service Mesh 并不是什么新技术,它所关注的问题域比如请求的高效、可靠传输,服务发现和治理等有服务化的一天就已经存在。成体系的服务治理方案我们早前很多 传统 SOA、API 网关等就早有深入并已形成标准方法论和行业规范。社区也不乏这方面的最佳实践。那为什么到如今才催生出如此火爆的 Service Mesh?这一切的发生我认为关键点在于两个方面:首先微服务架构模式成为大规模分布式应用的主流架构被大家所熟知与认可;其次云计算、容器化技术的规模化落地。越来越多的团队和组织开始实践微服务。这个时机很重要。
大家很清楚,微服务架构的核心在于基于分而治之理念的服务拆解,而拆解往往使原先可能一次内部方法调用就获取的结果,转换为一次或多次网络调用,我们都知道网络本身是不可靠的(这也正是为何 Service Mesh 解决的核心问题域中始终将请求的可靠传输放在至关重要位置的原因),下面我们简单梳理服务的拆解给我们带来的挑战:
拆解后,服务间依赖不可靠的网络进行通信;
缺少一套整体的方案来解决所谓东西向(横向)服务连通性的问题;
如何保证拆解后整体业务的稳定性(一次业务处理可能依赖数次微服务调用);
如何治理这些拆解后的服务(甚至是异构的微服务体系);
如何规模化、标准化更高效的实施、运维整个微服务体系。
图二:单体服务到微服务架构转变引发的调用方式的改变(依赖网络)
过去通常使用微服务治理框架、API 网关等方案来解决上面的问题。比如微博早在 2013 年就开始基于 Motan RPC 框架来解决服务治理的问题,而更早的 API 网关方案也具备相应的服务发现和治理能力甚至比微服务框架出现的还要早。传统微服务框架通过胖客户端的方式提供服务发现与治理能力。但是这种方式有诸多弊端:
与业务无关的服务治理逻辑与业务代码强耦合;
框架、SDK 的升级与业务代码强绑定;
多语言的胖客户端支持起来性价比极低;
各种语言的服务治理能力天差地别,服务质量体系难以统一。
图三:传统 SOA 方案(服务治理框架与 API 网关)
而 API 网关通常部署在集群的边缘,作为业务接入层,虽具备一些通用的服务治理能力,然而其本身的实现相对更重、且往往性能低下,因为它专注于 API 管理,流经 API 网关的所有流量都会经过很多通用逻辑,比如鉴权、验证、路由等,在传统的 API 网关场景,长达几十甚至过百毫秒的延迟对南北向的流量来说基本可以接受,但这在处理微服务体系内东西向流量时,这样的性能是不能容忍的,而且服务的拆分势必导致整个体系内东西向流量随着微服务规模的扩大而剧增。所以 API 网关并不能胜任微服务场景下的流量管理任务,它本身也不是为此而生的。
再补充一点很多人对 Service Mesh 和 API 网关分不清楚,正好这两种方案我都经历过,其实很简单:虽然它们都有服务治理能力,但彼此专注的点不一样,Mesh 关注内部服务间的互联互通,核心在于 Sidecar 构建的那张网格以及对应流量及服务的治理,而 API 网关更多关注的是 API 的管理,甚至不乏像 Apigee 这样全生命周期的 API 网关方案。
所以本质上 Service Mesh 的出现就是为了解决大规模微服务架构下,请求的高效可靠传输与服务治理的问题。它将原先实现在微服务框架胖客户端或者 API 网关接入层的服务治理功能下沉到一个统一的 Sidecar 代理以一个独立进程的方式部署在业务进程旁边,通过控制面来保障服务间通信的横向流量按照业务的真实需求在整个微服务体系内高效流转,因此 Service Mesh 不是服务治理框架,不是 API 网关更不是 istio。它是一种新兴的微服务实施模式。一种微服务治理的标准规范。它有很多种实现,istio 是目前最为大家所熟知的实现。不过下面我们要看的是微博自研的实现——WeiboMesh。
图四:Service Mesh 的方案其实是服务通信及治理功能的下沉与解耦
了解过 WeiboMesh 的同学可能知道,它是基于微博早期服务治理 RPC 框架 Motan 演变而来,(没了解过的同学可以 Google “微博 Service Mesh”,这里不再赘述)。微博平台的微服务体系建设做得比较早,平台内部技术主要是 Java 栈,基于服务治理框架和混合云有一整套服务化体系。同时平台还给其它兄弟团队提供底层数据与存储资源支撑。数据通过 Restful 接口提供。是一个典型的异构体系服务化整合的场景。随着平台微服务规模的增大以及业务复杂度的提高,我们必须面对以下三个难题:
热点、突发事件所引发流量洪峰(数倍甚至十多倍的剧增)的应对(要求高效、完备的服务治理体系);
混合云微服务架构下的复杂服务拓扑与依赖带来的冗长的调用链路、低效的请求长尾与及其复杂的故障排查;
各语言服务治理能力差异性引入的异构系统服务治理体系建设难题。
为了应对这些难题,我们摸索了一套 Service Mesh 实现方案。这里我先对整个方案的几个核心点做个简单描述(希望大家能从微博的场景中体会这种方案选取的出发点):
将以往在 Motan RPC 胖客户端实现的服务发现和治理功能下沉到 Motan-Agent 这个 Sidecar 代理上,通过对服务的订阅和发现来建立服务间依赖的逻辑网络,作为 WeiboMesh 的数据面。
复用 Motan RPC 的 Filter 机制,在 Cluster(服务集群) 和 Endpoint(节点)两个维度实现了 Service Mesh 的控制面逻辑,完成对服务间通信流量的管控,作为 WeiboMesh 的控制面。
服务注册和发现依赖微博故有的自研 Vintage 命名和配置服务。WeiboMesh 不与任何平台耦合,可运行在裸机、公 / 私有云、混合云的场景。
实现全新语言无关的通信协议 Motan2 和跨语言友好的数据序列化协议 Simple 来应对跨语言。通过为所支持的语言开发标准的 Motan2 客户端,完成与 Mesh 的通信(对业务较低的侵入性带来平台能力的整体输出,比如我们提供的各种数据服务化、存储资源服务化能力。这个方案的性价比极高,而且保证整体架构向前演进而非推倒重来,这在微博大体量的业务需求下显得格外重要,而且我们跨语言的 SDK 只保留极薄的一层,仅保证使用 Simple 序列化在 Motan2 协议上传输请求而已,这很好的控制了整体维护成本)。
图五:WeiboMesh 方案(理想的终极方案)
这是我们探索了各种跨语言服务化方式后,最终第一版上线时的方案(之前的文章有对此详尽的描述,请自行 Google,同样不再赘述),也是一个迄今为止我们依然认为比较理想(符合微博现状)的 Service Mesh 方案。最大程度上复用了我们多年来在 Java 体系以及混合云架构下积累的服务化经验。最大化地保证了平台技术体系的稳固、高效同时兼顾了极低的接入、升级、维护成本。
为什么说理想很丰满,现实很骨感。整个 WeiboMesh 项目组最初由服务框架组与 Feed 组主导协同多个业务方共建(立项时叫跨语言服务化小组),参与方涉及五、六个团队,且参与各方都对跨语言服务化有重度需求,一点不夸张的讲已经是痛不欲生苦不堪言才逼到这条路上来(经常为排查一个线上问题,要追踪无数跳的链路,打日志、加监控,费时费力效果还不理想;四七层的转发也增大了请求时延;因为请求双方服务池的不一致导致跨云转发,请求长尾严重等)。
所以最初参与的各方,状态和心境都非常积极,大家很主动的推进整个方案演进、调研、试错。服务端改造过 GRPC 方案、Yar 方案、Servlet 转 Motan2 的方案等等,客户端也改造过很多方案,比如服务在 Client 端的描述、Client 的构造方式、请求的组织形式、各种兜底方案等等。所以第一版上线时,我们其实已经经历了很多尝试与磨合。还算比较成功,我们原型版早在 16 年底就已经初步线上试水,17 年已经直接抵御春晚的高峰。
但是往下想把这种理想的方案铺开来时,现实开始向我们展现出它的骨感。可谓一步一坎:
如何说服项目组外其他各方在新业务上应用 Mesh 方案;
如何将老业务接入 Mesh 体系,现有方案 Server、Client 两端都没做到完全零侵入;
Agent 引入的运维复杂度和权责划分。
我们除了需要消除大家对 Mesh 性能和稳定性的顾虑,还要保证方案足够简单,避免对已有的运维体系,服务开发、部署模式造成太大的冲击,同时要让大家认可 Mesh 改造的收益,用数据和效果说话。
图六:Mesh 接入的一个典型收益示例(双发带来延时的削峰填谷)
虽然有搜索、微博主站 Page、热门、话题这样的一些重量级典型业务方给我们的方案背书,从以往的 Restful 方案接入 Mesh 后,享受到性能提升的同时也收获了平台服务治理体系的红利,因为有些业务方专注于自己的业务领域,很正常在服务治理及相关体系建设方面会相对薄弱。
对于业务方接入我们的方案已经足够简单,只需要多部署一个 Sidecar 代理,将以往的 Restful 调用迁移到我们的跨语言 SDK 上即可,业务方不需要关注 Sidecar 的任何事情,因为当 Sidecar 出问题时,我们可以退化为 Restful 调用,并立即报警。
同时我们 Mesh 体系提供了缓存、队列等服务化资源,通过 SDK 既可以轻松访问,业务方可以由此对自己依赖的服务和资源都有整体治理的能力。对于 SDK 接入这样的改造,显然性价比是极高的。然而现实情况是,很多时候可能因为业务开发压力等原因,他们并没有太多的精力来完成这样的改造。
而另一方面,平台内部已有的大量老业务如何接入 Mesh 体系?现今平台业务已经处于一个相对稳定的阶段,老业务才是改造的重中之重,我们必须在 Mesh 体系为业务方准备好他们依赖的服务。但是 Mesh 方案能为平台服务方提供的唯一好处可能就是接入后,他们不再需要同时维护 RPC 和 Restful 两套服务,但是对于本来就已经历经风雨稳定运行的平台服务来说,已有的 Restful 服务没什么不好,为什么要去改造?显然大家是不乐意的,虽然我们已经在 Motan RPC 框架层面做了诸多努力,甚至做到只需修改一行配置,多导出一个 Motan2 服务即可,那又如何?服务端的变更要求非常严谨,一行配置同样需要经过整个上线流程。婉拒的话术通常是诸如“目前业务比较忙,往后有空再具体规划”此类。
这迫使我们一直在思考一个问题“如果要让 xxx 接入 Mesh,需要 xxx 做什么?我们需要支持什么?”,这也促使 WeiboMesh 迎来了全新的一次演进 ——HTTPMesh。
HTTPMesh 的目标在于,不需要修改任何一行代码,真正做到对业务零侵入接入,具体做法:
将现有 Restful 接口自动导入 Mesh 体系;
通过 HTTP_PROXY 将客户端流量指向 Sidecar。
我们通过解析平台 Restful 服务对应的 Nginx 配置,将 Restful 接口自动对应到 Mesh 体系的 RPC 服务上,Nginx 的 upstream 与 RPC 的 Service 对应,Restful 服务池与 PRC 服务分组对应,这样一来原来的 Restful 服务在 Mesh 体系就有了相应的表示。
图七:HTTPMesh 方案
新增业务只需提供一套 Motan2 服务,而非以往的 RPC 和 Restful 两套。老业务的场景,服务端 Agent 充当反向 HTTP 代理,将进入的 RPC 请求转换为 HTTP 请求转发到之前的 Restful 接口;客户端我们在 Sidecar 代理上提供了 HTTP 的正向代理支持,通过 HTTP_PROXY 将本地出口的 HTTP 请求都指向 Sidecar,这样如果 Sidecar 发现请求已经导入 Mesh 体系则会将代理的 HTTP 请求转换为 RPC 请求转发进入 Mesh 网格,否则将 HTTP 请求透传发出;而新开发的采用了 SDK 方案的服务可以同时享有平台所有资源、服务及治理体系。这样双方接入都不需要做任何改动。
解决了双方改造成本的大问题,接下来就是引入 Sidecar 对运维流程的影响和权责划分的问题。在业务进程旁运行 Sidecar 来处理进出流量,需要在固有的运维流程中添加对 Sidecar 的运维,这看似简单的操作,实则涉及多方面的问题:
Mesh 进程与业务进程的启停(时序、优雅停机);
Mesh 进程的升级维护;
Mesh 进程的监控、报警;
故障处理与恢复。
运维方面可能各公司情况不一,包括我们内部,不同团队可能姿势都不完全一样,不具有通用性,所以这里不展开太多,只想说明一点我们为了应对各种场景和姿势,我们在 Mesh 上提供了管理端口、后端探测等功能,比如运维可以通过向 Mesh 管理端口发起上下线请求来触发 Mesh 自动上下线服务,也可以通过配置探测地址及状态来对业务进程进行健康检查指导该节点上下线或告警,另外我们提供了多种发布方式,镜像、RPM 包等一应俱全,便于运维挑选适合自己生产的部署方式,我们还将 Mesh 配置做了统一的管理,因为以往接入的经验来看,80% 场景使用通用配置即可,只有很少的 20%,甚至更少的场景需要个性化配置,那样也减少大家理解和我们作为方案提供方的指导成本。所有 Mesh 相关的包、库和配置都由我们提供,这样也有了明晰的权责划分,我们为 Mesh 负责,降低业务方的心智负担。
就这样,我们在 WeiboMesh 的路上继续前行。因为我们深知微服务、云计算才是稳定服务的正道。确实给我们带来了很多现实收益,而且我们相信这些收益仍在不断放大。
前面我们探讨了 Service Mesh 的本质,分享了一些 WeiboMesh 实践过程中的经验,下面我们来讨论下如何落地 Service Mesh。
Service Mesh 很好的解决了规模化微服务架构下服务通信和治理的问题,给我们带来了很多确确实实的好处,网络上相关的解读很多了我就不再次啰嗦。这里我只想根据自己的实践和理解,梳理出一些我认为很适合引入 Service Mesh 的场景,希望能帮助大家更好的做出判断:
还未进行任何形式服务化;有的初创团队可能先期并没有太多精力来进行技术建设,但是技术的稳定性是业务增长的基石,Service Mesh 的整套的微服务治理方案正好是个不错的选择,先期可能不需要对服务做太细粒度的拆分,可以基于 Mesh 体系来构建,逐步接入、分解;
有跨语言互通需求;这不用多说,WeiboMesh 就是这方面实践的一个务实的好例子;
内部服务依赖重(东西向流量);有些业务可能同时依赖很多服务,一次请求对应数次 Restful 请求,有繁重的网络 I/O 需要处理,可以引入 Service Mesh 来保障这些请求的可靠性;
依赖传统的服务化框架做服务治理;这里主要指服务治理与业务逻辑强耦合的场景,前面也讨论过这种方案的各种弊端,引入 Service Mesh 将服务治理逻辑与业务逻辑解耦,应用开发的同学只需专注自己的业务,这是最好的选择;
技术建设与前瞻性;云计算与微服务为提高服务构建效率、降低投入成本提供了可能性,这里面的想象空间是巨大的,从大厂在此方面的投入可见一斑,俗话说的好,钱在哪儿方向就在哪儿。具有前瞻性的技术储备将为组织迎接各种挑战提供坚实后盾。
想清楚我们确实需要落地 Service Mesh,认可其带来的巨大收益,剩下的就是 Service Mesh 方案的选择了。我们需要制定一个可执行的 Service Mesh 实施方案。还是那个老生常谈的话题:“选择自研、开源还是基于开源微创新?”。在这方面我只有一条建议:“因地制宜,不盲目跟风”。选择的过程中,头脑一定要清晰,仔细分析自己的场景和业务痛点,调研与自己场景最贴合的开源方案,过程中掂量自己可支配的资源以及项目周期同时关注方案复杂度。尽量避免重复造轮子。
不过事实上开源方案一般考虑比较通用的场景,很难有能与自己场景完全吻合。这时候为了控制成本更多会选择基于开源进行改造。这就引入了一个与开源共建的问题。应该避免独立 fork 导致后期离开源越走越远。
Service Mesh 从出现到现在两年多的时间里可谓发展迅猛,这离不开社区大家的热情,抛开大厂在前面带风向不说,技术本身确实有很多先进性,不管是否入坑 Service Mesh,作为一个工程师我觉得都应该深入了解,学习这种 Mesh 思考模式和工程化、标准化思想。希望本文能给你带来一些思考。
周晶,新浪微博平台研发技术专家,负责微博跨语言微服化框架开发以及 ServiceMesh 技术落地等,OpenResty 社区委员会成员,高性能 OpenResty 开发框架 Vanilla 作者,开源爱好者,关注微服务、 API 网关、云原生等技术。
同时,周晶还会在 QCon 全球软件开发大会(广州站)分享题为「微博 Service Mesh 实践」的话题,感兴趣的同学可以关注下。
点个在看少个 bug
1、头条易读遵循行业规范,任何转载的稿件都会明确标注作者和来源;
2、本文内容来自“InfoQ”微信公众号,文章版权归InfoQ公众号所有。