作者 | 至简 阿里云高级技术专家
随着微服务软件架构在互联网企业的广泛实践,新一代微服务软件架构技术悄然兴起,Service Mesh 便是其中之一。
根据 Linkerd CEO Willian Morgan 对 Service Mesh 的定义,Service Mesh 是一层处理服务间通信的基础设施。云原生应用有着复杂的服务拓扑,Service Mesh 保证请求可以在这些拓扑中安全且可靠地穿梭,对整个服务网络进行观测和高效查错,以及通过灵活的流量治理能力为新功能上线提供高效的验证手段。在实际应用当中,Service Mesh 通常是由一系列轻量级的网络代理(又被称为 Sidecar)组成的,它们部署在应用进程的边上且对应用进程完全无感。
国内 Service Mesh 早期实践基本分为先建设数据层后建设控制层和同时建设两类,从后续发展看,随着对服务运营能力要求的提高,控制层会越来越重要。在实际落地方面,众多企业都在积极探索 Service Mesh 在大规模场景下的应用。
阿里巴巴高级技术专家至简在 KubeCon 2020 阿里巴巴云原生专场分享了《Service Mesh 在超大规模场景下的落地挑战》,基于阿里巴巴的落地实践,分享一些经验和思路。以下是部分内容整理。
分布式应用架构在阿里巴巴的现状
阿里巴巴围绕电商业务构建了庞大的微服务软件架构应用生态,包括了天猫、淘宝、菜鸟、高德等。其次,整个微服务体系是通过 Dubbo RPC 连接在一起,MetaQ 用于服务之间的异步解耦。
目前阿里巴巴主要的技术栈还是 Java,围绕 Java 构建了相当健全的微服务治理能力,其他技术栈的微服务治理能力相对弱很多。在服务可见性这块,阿里巴巴是完全没有隔离的。Dubbo RPC 仍是接口级服务发现,1 个应用如果提供 10 个接口,那么就会有 10 个服务是可以被发现的,如果这个应用有 n 台机器,那么 10 个服务就会产生 10*n 个服务端点元信息,这种重复数据导致规模问题被放大。
另外一点值得跟大家分享的是,目前阿里巴巴也正经历着应用的 SDK 升级之痛,SDK 中包含了中间件和应用层的一些公共模块,由中间件统一以 Pandora 包的形式交付给业务方使用。在应用数非常庞大的情形下,SDK 升级是一份相当繁重的工作,甚至涉及到集团层面的大协同。为此,我们希望通过 Service Mesh 先将中间件的那些能力下沉到 Sidecar,将这块升级工作从 Pandora 中剥离出来,借助 Service Mesh 的流量无损热升级能力让业务对中间件升级完全无感。
Service Mesh 面临的挑战
- Service Mesh 面临的第一个挑战就是新技术如何平滑演进;
Service Mesh 在大规模场景下的落地在业界的案例还相当 少,根源在于该技术本身还没有完全成熟。在技术走向成熟的持续迭代过程中,如何平滑演进是一个很有挑战的任务。挑战在于需要以终为始地规范技术架构的演进,一步一步地向终态架构演进。
- 第二个挑战是发展的过程中如何协调好技术和业务的平衡;
技术团队希望快速迭代向前发展兑现价值,而业务团队每年有自己的业务目标,如何协调好两者的发展关系是个不小的挑战。代表新技术的团队其发展思路通常会更激进,而业务团队会因为“稳定压倒一切”而偏保守,短期内调和好这一矛盾或许需要自顶向下的决策力量,否则业务挑战年年有而可能挤压技术的发展空间,导致技术发展缓慢而无法更好地服务于业务的发展。
- 第三个挑战是技术向前演进时如何处置历史包袱;
每一次技术的演进都意味着对原有技术体系的升级,这就不可避免地需要处置过往累积下来的技术债。新技术发展的难点往往不在于其“新”,而在于包袱太重而导致新技术演进困难,很可能因为演进太慢而严重影响了新技术的发展。
- 第四个挑战就是克服超大规模所带来的问题;
前面讲到的 Dubbo 因为是接口级服务发现,使得服务发现的数据规模非常大,给控制平面的端点数据推送能力带去了巨大挑战。
- 最后一个挑战是 Sidecar 的规模化运维。
在超大规模场景下,大量的应用机器意味着有等量的 Sidecar 需要运维,如何在部署、灰度、升级以及保障安全生产是一个很大的挑战。
新技术在架构上平滑演进是关键
新技术的不成熟很可能在相当长的一段时间内是常态,演进的关键在于如何实现新技术架构的平滑演进,避免出现推倒重来这种劳命伤财之事。为此,基于这一考量,我们一共经历了“起步”、“三位一体”和“规模化落地”三大阶段,而每一个阶段采用了不同的软件架构或部署方案。
在起步阶段,Istio 控制平面的 Pilot 组件放在一个单独的容器中,同时当作一个独立的进程和 Sidecar 部署在一个 Pod 里。采用这样的方式,使得对开源的 Envoy 和 Pilot 可以做最小的改动而加速落地,也方便我们基于开源的版本做能力增强和反哺。这一方案的缺点在于,每个 Pod 中都包含了一个 Pilot 进程,增大了应用所在机器上的资源消耗,因在服务规模并不大的情形下资源消耗相对小而可以忽视这一缺点。
在三位一体阶段,Pilot 进程从业务 Pod 中抽离了出来变成了一个独立的集群,在 Sidecar 和 Pilot 之间仍是 xDS 协议。这一架构虽节省了应用所在机器的资源消耗,但必须正视规模化落地的问题。xDS 中有一个叫 EDS(Endpoint Discovery Service)的协议,Pilot 通过 EDS 向 Sidecar 推送服务发现所需使用到的机器 IP(又被称之为 Endpoint)信息,在阿里的大规模场景下因为有大量的端点需要通过 Pilot 推送给 Sidecar,导致 Sidecar 的 CPU 消耗相当大,让人担心业务进程因为 Sidecar 对资源的争抢而受影响。这一规模化问题并非在起步阶段的技术方案中不存在,只不过因为那时落地应用的服务规模小而没有成为瓶颈。
为了解决规模化落地的问题,我们设计出了规模化落地的技术架构。
在这一架构中,虽然还是 Sidecar 对接 Pilot 集群,但是 Pilot 集群只提供 xDS 中的 LDS/CDS/RDS 这些标准的服务,而 EDS 采用 Sidecar 直接对接服务注册中心解决。值得强调,虽然Sidecar直接对服务接注册中心,但是它仍然沿用了 Envoy 里面对 EDS 所抽象的数据结构和服务模型,只是在数据的获取上对接注册中心来实现。之所以 Sidecar 直接对接服务注册中心能解决走 EDS 所存在的规模化问题,根源在于阿里巴巴的服务注册中心具备了增量推送的能力。
在这三种架构中,未来的终态一定是采用三位一体的架构,且数据平面和控制平面也一定是并重发展。由于阿里巴巴今天的服务规模非常庞大而没办法一步到位做到三位一体。通过规模化落地这一过渡方案,仍然有助于我们更好地反哺开源社区,通过尽早大规模落地会让我们清楚地知道开源方案仍存在的问题,从而让我们能为开源方案的完善做出更大的贡献。
业务与技术协同发展 —— 飞行中更换引擎
业务与技术的协同发展首先要回答好一个问题,即新技术带给业务的价值是什么。从业务的角度,采纳新技术最开始考虑的一定是短期价值,然后才是放眼看长远价值。
Service Mesh 对于业务所带去的短期价值是:
中间件能力下沉,下沉的过程中去除历史包袱轻装上阵;
业务对中间件升级无感,中间件资源消耗可量化、优化可度量。
从长远来看,完全解决阿里巴巴面临的 Pandora/SDK 升级之痛是需要相当长的一段时间,而 Service Mesh 在流量治理这块的新价值也需要规模化落地达到一定水平后才能兑现,基础技术对业务的价值需要具备长远的眼光。Service Mesh 的长远价值有:
业务与基础技术全面解耦,业务更聚集于自身而加速创新,基础技术独立演进而加速迭代;
对微服务生态完成标准化、体系化的收口与治理,收敛故障和促进安全生产,加速应用功能正确性的验证效率;
为多种编程语言的应用提供微服务治理能力,完善并丰富云原生多编程语言的应用生态;
共建全球事实标准,通过阿里云的产品落实客户 IT 设施的多云和混合云战略,加速中国社会乃至全球的数字化转型。
明确了技术的价值之后,业务与技术协同发展接下来的挑战在于,需要技术演进的过程中完全不影响业务,这好比给一架高速运行的飞机换引擎。为此,新技术的落地方案需要考虑对业务无侵入,换句话说规避业务应用新技术的改造成本。
为了应用 mesh 化时对业务无感,在以 RPC 流量做 mesh 化为切入点的背景下,我们设计了动态流量无损透明拦截的技术方案。上图示例说明了应用 mesh 化前后的三种状态。在“过去”,流量是直接通过 RPC SDK 在 Provider 和 Consumer 之间互通的,SDK 直接跟中间件的服务注册中心、配置中心对接。
到了“现在”,Service Mesh 直接被插入到了应用和中间件之间,SDK 不做任何的变化,但通过 iptables 将 SDK 的流量拦截到 Sidecar 中。由于 iptables 是否开启和关闭流量拦截是可以通过运维控制台从应用或机器维度进行控制的,这就使得在 mesh 技术自身出现问题的情形下可以方便禁用,让应用回退到通过 SDK 直连的方式互通。
面向“未来”,当 Service Mesh 技术完全成熟时,SDK 需要从“胖”变“瘦”,那时并不需要 SDK 中存在下沉到 Sidecar 的那些能力,从而节约重复功能所导致的资源开销。
下图示例说明了打开和关闭流量透明拦截功能的关键流程。其中应用进程中包含了 RPC SDK 而没有区分表达,Traffic Interceptor、Pilot Agent 和 Envoy 三个组件在同一个容器中,所有组件共享同一个 Pod。OneOps Core 是基于 K8s 所构建的中心化 mesh 运维 Operator,收到控制台(图中标识为小人的 Operator 指代)调用开启或关闭流量透明拦截的接口后,通过调用 Pilot Agent 所提供的接口完成对 Pod 中应用流量的操作。
为了保证打开和关闭透明拦截功能时无业务流量的调用损失,请注意图中红色标识出的二大块流程。开启流量拦截时:Pilot Agent 将调用 RPC SDK 的 offline 接口(消息 2.1.1),间接完成从服务注册中心对本机做去注册摘除流量;然后调用 Traffic Interceptor 组件所提供的接口开启流量拦截功能(消息 2.1.2);最后再调用 RPC SDK 的 online 接口将本机注册到服务注册中心(消息 2.1.3)。
关闭流量拦截时:Pilot Agent 将调用 Envoy 的优雅关闭接口(消息 4.1.1),Envoy 会在 RPC SDK 与 Envoy 建立的连接上透传这一消息(即 Envoy 会调用 RPC SDK 的优雅关闭接口,上图并没有表达出),告诉 RPC SDK 不要再向已建立的这一长连接上发送任何 RPC 请求;随后 Pilot Agent 调用 Traffic Interceptor 接口关闭流量拦截功能(消息 4.1.2);最后,Envoy 的优雅关闭接口被调用时会启动一个延时 15 秒的定时器,确保 RPC SDK 与 Envoy 间已建立的长连接上还没有完成处理的请求有足够的时间处理完以免出现流量有损,当定时器到期后 Envoy 会主动关闭与 RPC SDK 所建立的连接(消息 6)。
为了让 mesh 技术自身的迭代对业务无感,我们设计了流量无损热升级方案,确保 Sidecar 可以随时对业务无感升级。设计流量无损热升级方案的核心考量是投入产出比,以最小的工程成本构建一个容易做到稳定的技术方案,下图示例了站在 Consumer 视角(即 Consumer 侧的 Envoy 进行升级,Consumer 代表流量调用的发起方)所观测到的热升级流程。
当 Envoy 有一个新版本需要升级时(图中标识为 v2),通过运维控制台可以设置这个新版本的镜像信息,通过 OpenKruise 的 SidecarSet 可以拉到这一镜像并将镜像中的新版本 Envoy 二进制程序拉起。随后,新版本 Envoy 会向老版本 Envoy(路中标识为v1)发起热升级流程。
热升级大致包含如下几个流程:老版本进程中所有的侦听 fd 通过进程间通讯的方式交给新版本进程(消息 5.1),由新版本进程继续在之上进行侦听(消息 5.1.1),换句话说,之后所有在这些被侦听端口上新建的连接都会发生在新版本进程中;老版本进程调用 RPC SDK 的优雅关闭接口(消息 5.3),告诉 RPC SDK 不要再已建立的连接上发起新的调用,如果要发起新调用则必须重新建立连接,显然新连接将与新版本进程建立,随后的调用流量将全部进到新版本进程;老版本进程向 RPC SDK 发起优雅关闭接口调用的同时会建立一个时延 15 秒的定时器,确保与 RPC SDK 所建立的连接在这 15 秒中都处理完,定时器到期后关闭这一连接并退出老版本进程(消息 5.4),从而结束整个热升级流程。
下图是从 Provider 视角(即 Provider 侧的 Envoy 进行升级,Provider 代表提供相应服务能力的被调用方)所观察到的升级流程。不难看出,红色标识出的部分与前一张图是完全一样的,热升级流程完全无需基于 Envoy 的 Consumer 或 Provider 身份做特殊的处理。毕竟,现实中每个应用大多会同时承担 Consumer 和 Provider 两种角色。
上图有一个点值得特别指出,Envoy 需要实现序号为 5.3 的优雅关闭消息,并将这一消息透传给 RPC SDK(图中并没有表达)。
发展新技术是偿还技术债的重要契机
不少新技术的出现多少会引发我们的纠结,在新技术所创造的短期价值不那么有吸引力的情形下,似乎旧技术不改变就不会带来风险。但经验表明,不改变的后果是包袱会越积越重,由此所带来的技术债的潜在风险最终都不可忽视。
技术债是软件的本质属性,因为无法做到已有架构能一直百分百优雅实现新需求。换句话说,技术债对于一个长期提供服务的软件来说是一直存在的,只不过存在大小之别和何时偿还的问题。
阿里巴巴对分布式系统的探索有超过十年的积累,为了做应用的服务化改造提出了 HSF RPC 开发框架并将之开源为 Dubbo。基于框架思维所构建的 RPC 协议为了更好地满足不同业务对服务路由的定制化诉求,提供了通过 Groovy 脚本进行定制的能力。然而,这种灵活的手段在向 Service Mesh 这一平台技术演进时将带来流量治理隐患。
我们认为,平台思维下构建的 Service Mesh 得限制过于灵活的定制能力,避免平台出现“窟窿”而无法有效、有力地完成全局最优的治理。为此,我们将去除 Groovy 脚本当作是一项技术债加以偿还。Groovy 脚本带来的问题主要有两个:
过于灵活且导致了开发框架与应用代码的耦合;
给流量治理能力下沉留下了潜在隐患。
为了去除 Groovy 脚本,我们扩展了 Istio 的 VirtualService 和 DestinationRule,抽象出按应用名、方法和参数路由的能力。下图示例说明了某应用基于应用名做路由在 Groovy 脚本和 Service Mesh 下的具体实现。
由于单个应用的 Service Mesh 化并非一刀切的一次性完成,存在一个应用的部分机器先 mesh 化做灰度的场景。为此,需要在去 Groovy 脚本这件事上,让新旧技术方案能同时无缝工作,背后是两种形式的路由表达如何做好同步,背后就涉及控制台收口和格式转化等问题需要妥善解决。
系统性解决超大规模问题
为了最终解决阿里巴巴在 Service Mesh 落地过程中所面临的大规模问题,我们从三个方面着手:
Service Mesh 技术自身的持续优化:需要从 CPU 开销、内存占用和时延三大维度进行持续优化,通过软硬件结合等技术手段做到应用 Service Mesh 化前后零新增成本甚至下降;
Dubbo 实现应用级服务发现而非接口级:通过应用级服务发现将使得控制平面向数据平面推送的服务元数据有数量级下降,让 Service Mesh 的控制平面向数据平面推送的数据急剧下降。
服务注册数据进行单元封闭并分级治理:动机依然是降低 Service Mesh 控制平面向数据平面推送的数据量,通过单元封闭让全局服务元数据通过局部化而减少。
这三方面在阿里巴巴分别有相应的团队在探索解决,这里主要分享 Service Mesh 技术本身。阿里巴巴对 Service Mesh 技术的探索策略是“借力开源,反哺开源”。
“借力”体现于整体技术方案采纳的是开源的 Istio(控制平面) + Envoy(数据平面),在工程实践中特别注意自有代码与开源代码做充分的解耦,以及频繁跟进开源社区发布的新版本;
“反哺”表现在我们积极将性能优化、bugfix 等代码提交给开源社区。
至今,在 Istio 开源社区我们提交了 9 个 PR,解决性能问题和 bugfix;在 Envoy 开源社区我们提交了 14 个 PR,包含内存开销下降 50% 的优化、新增对 Dubbo 和 RocketMQ 协议的支持等内容。此外,我们曾与 Istio 社区共同探索实现了 EGDS (Endpoint Group Discovery Service),作为 EDS 的增强,但由于 Envoy 社区担心该 feature 通用性不足而最终没能接受而完成这次反哺。这一“失败”不只体现了我们反哺社区的意愿和热情,也是更好融入开源社区的一次很好的学习机会。
在 EGDS 并不能很好解决在“三位一体”方案下的大规模落地问题的情形下,我们重新调整了落地方案,形成了本文前面所讲到的让 Envoy 直接对接服务注册中心的“规模化落地”方案。下图展示了两个方案的 CPU 开销数据比较。
图中深蓝色代表的是规模化落地方案,橙色代表的是三位一体的方案,测试数据表明三位一体方案在设定的越大规模压测场景下因服务元数据推送给 Envoy 所带去的 CPU 开销是规模化落地方案的三倍。
进一步地,我们比对了非 mesh 方案和规模化落地 mesh 方案因服务元数据推送所导致的 CPU 开销(如下图所示)。数据表明,非 mesh 方案(图中橙色表示)因 Java 进程在数据推送场景下存在 GC 而使得 CPU 开销要显著地高于规模化落地 mesh 方案(图中深蓝色表示),这是因 Envoy 采用 C++ 编程语言而获得的优势。
后续我们会考虑参与共建 Envoy 社区所提出的 LEDS 协议,让 Istio + Envoy 的三位一体方案天然地能运用于阿里巴巴的大规模场景。
除了 CPU 开销的优化,我们在内存优化方面也取得了巨大的进展。同样服务规模的情形下,Envoy 的内存开销从之前超过 3G 优化至 500M 左右。此外,压测数据表明应用 mesh 化完成后整体内存开销比 mesh 化前更低。
Sidecar 的规模化运维
Sidecar 的规模化运维也是很具挑战的一件事,内容包含 Sidecar 的部署、灰度、升级,以及需要构建相应的监控和报警设施。
Sidecar 的部署、灰度、升级我们全面基于由阿里巴巴开源的 OpenKruise 中的 SidecarSet 实现。SidecarSet 提供了对 Sidecar 进行部署、灰度和升级的通用能力,能很好地运用于 Service Mesh 而省去了重复建设。
当然,流量无损热升级这样的能力并非 SidecarSet 原生提供的,需要从 Service Mesh 层面去增强。在 Sidecar 的运维和流量治理这块,监控和报警全面采用了阿里云上的 Prometheus 和 ARMS 两大云产品,一旦当下服务于阿里巴巴内部的 Service Mesh 技术将来要通过产品化输送给阿里云上的客户时会更加方便。
在运维管控上,我们全新构建了云原生 OneOps 运维系统。OneOps 包含控制台和 OneOps Core 两大子系统。后者是基于 K8s 构建的运维 Operator,通过 CRD 的形式暴露给控制台调用接口。OneOps Core 可以多区域部署,而控制台是全局集中部署的,这样方便运维人员在同一个控制台上能无缝地管理多个区域的 Service Mesh。目前 OneOps 已具备管理包含了 Sidecar 和 Ingress Gateway在内的东西南北向流量的能力。
总结
本文总结了阿里巴巴大规模落地 Service Mesh 所面临并克服的技术挑战,希望这些内容对行业同仁在这一技术的探索和学习有所帮助。现阶段,阿里巴巴对于 Service Mesh 的探索更多停留于解决历史包袱和完成应用与中间件的解耦,仍没有在服务流量治理方面做出新价值和新体验,期待未来能尽早给大家分享这方面的内容。
Service Mesh 是云原生的关键技术,对于阿里巴巴来说,我们笃定这是分布式应用微服务软件架构的未来。正因如此,CTO 鲁肃也站台 Service Mesh 技术,并做出了未来整个经济体全面走 Istio + Envoy 方案的技术决策。在构建阿里巴巴全球商业操作系统的道路上,Service Mesh 是面向未来五年、甚至十年的技术。
期待更多对分布式应用相关技术挑战有热情的志同道合之士加入共建与共创,在创变的道路上我们共同成长、共同收获。**如果您有意向,请将简历发送至 zhijian.ly@alibaba-inc.com**,我们在深圳、上海和杭州都有 Service Mesh 的职位长期开放。
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”