Dubbo Mesh 在闲鱼生产环境中的落地实践

本文做者至简曾在 2018 QCon 上海站以《Service Mesh 的本质、价值和应用探索》为题作了一次分享,其中谈到了 Dubbo Mesh 的总体发展思路是“借力开源、反哺开源”,也讲到了 Service Mesh 在阿里巴巴的发路径将经历如下三大阶段:算法

  • 撬动
  • 作透价值渗透
  • 实现技术换代

Dubbo Mesh 在闲鱼生产环境的落地,分享的是以多语言为撬动点的阶段性总结。编程

文章首发于「QCon」,阿里巴巴中间件受权转载。缓存

闲鱼场景的特色

闲鱼采用的编程语言是 Dart,思路是经过 Flutter 和 Dart 实现 iOS、Android 两个客户端以及 Dart 服务端,以“三端一体”的思路去探索多端融合的高效软件开发模式。更多细节请参考做者同事陈新新在 2018 QCon 上海站的主题分享《Flutter & Dart 三端一体化开发》。本文将关注三端中的 Dart 服务端上运用 Dubbo Mesh 去解耦 Dubbo RPC 框架的初步实践成果。微信

Dart 服务端是一个服务调用胶水层,收到来自接入网关发来的 HTTP 请求后,经过 C++ SDK 调用集团普遍提供的 Dubbo 服务完成业务逻辑处理后返回结果。然而,C++ SDK 的功能与 Java 的存在必定的差距,好比缺失限流降级等对于保障大促稳定性很重要的功能。从长远发展的角度,闲鱼团队但愿经过 Dubbo Mesh 能屏蔽或简化不一样技术栈使用中间件(好比,RPC、限流降级、监控、配置管理等)的复杂性。这一诉求的由来,是闲鱼团队经过几个月的实践,发如今 Dart 语言中经过 C++ SDK 逐个接入不一样中间件存在定制和维护成本高的问题。值得说明,所谓的“定制”是由于 C++ SDK 的能力弱于 Java SDK 而要作补齐所致。架构

Dart 服务端自身的业务逻辑很轻且在一些场景下须要调用 20 屡次 Dubbo 服务,这对于 Dubbo Mesh 的技术挑战会显得更大。在 Dubbo Mesh 还没在生产环境落地过而缺少第一手数据的情形下,其性能是否彻底知足业务的要求是你们广泛关心的。并发

架构与实现

Dubbo Mesh 架构图(监控部分未表达)

Dubbo Mesh 架构图(监控部分未表达)框架

图中的虚框表明了一个Pouch容器(也能够是一台物理机或虚拟机)。左边两个容器部署了 Dubbo Mesh,剩下最右边的则没有。目前 Dubbo Mesh 主要包含 Bonder、Pilot、Envoy 三个进程,以及被轻量化的 Thin SDK。其中:less

  • Envoy 承担了数据平面的角色,全部 mesh 流量将由它完成服务发现与路由而中转。Envoy 由 Lyft 初创且目前成为了 CNCF 的毕业项目,咱们在之上增长了对 Dubbo 协议的支持,并将之反哺到了开源社区(还有很多代码在等待社区 review 经过后才能进到 GitHub 的代码仓库)。
  • Pilot 和 Bonder 共同承担控制平面的角色,实现服务注册、进程拉起与保活、集群信息和配置推送等功能。Pilot 进程的代码源于开源 Istio 的 pilot-discovery 组件,咱们针对阿里巴巴集团环境作了必定的改造(好比,与Nacos进行适配去访问服务注册中心),且采用下沉到应用机器的方式进行部署,这一点与开源的集群化部署很不同。背后的思考是,Pilot 的集群化部署对于大规模集群信息的同步是很是大的一个挑战,今天开源的 Istio 并不具有这一能力,将来须要 Nacos 团队对之进行加强,在没有彻底准备好前经过下沉部署的方式能加速 Service Mesh 的探索历程。
  • Thin SDK 是 Fat SDK 通过裁剪后只保留了对 Dubbo 协议进行编解码的能力。为了容灾,当 Thin SDK 位于 Consumer 侧时增长了一条容灾通道,细节将在文后作进一步展开。

数据链路所有采用单条 TCP 长链接,这一点与非 mesh 场景是一致的。Pilot 与 Envoy 两进程间采用的是 gRPC/xDS 协议进行通信。编程语言

图中同时示例了 mesh 下的 Consumer 能同时调用 mesh 下的服务(图中以www.mesh.com 域名作示例)和非 mesh 下的服务(图中以 www.non-mesh.com 域名作示例)。闲鱼落地的场景为了不对 20 多个依赖服务进行改造,流量走的是 mesh 下的 Consumer 调用非 mesh 下的 Provider 这一形式,读者能够理解为图中最左边的容器部署的是 Dart 服务端,它将调用图中最右边容器所提供的服务去实现业务逻辑。分布式

容灾

从 Dubbo Mesh 下的 Provider 角度,因为一般是集群化部署的,当一个 Provider 出现问题(不管是 mesh 组件引发的,仍是 Provider 自身致使的)而使服务没法调通时,Consumer 侧的 Envoy 所实现的重试机制会将服务请求转发到其余 Provider。换句话说,集群化部署的 Provider 自然具有必定的容灾能力,在 mesh 场景下无需特别处理。

站在 Dubbo Mesh 的 Consumer 立场,若是彻底依赖 mesh 链路去调用 Provider,当 mesh 链路出现问题时则会致使全部服务都调不通,这每每会引起业务可用性问题。为此,Thin SDK 中提供了一个直连 Provider 的机制,只不过实现方式比 Fat SDK 轻量了许多。Thin SDK 会按期从 Envoy 的 Admin 接口获取所依赖服务的 Provider 的 IP 列表,以备检测到 mesh 链路存在问题时用于直连。好比,针对每个依赖的服务获取最多 10 个 Provider 的 IP 地址,当 mesh 链路不通时以 round robin 算法向这些 Provider 直接发起调用。因为容灾是针对 mesh 链路的短暂失败而准备的,因此 IP 地址的多少并非一个很是关键的点。Thin SDK 检测 mesh 链路的异常大体有以下场景:

  • 与 Envoy 的长链接出现中断,这是 Envoy 发生 crash 所致。
  • 所发起的服务调用收到 No Route Found、No Healthy Upstream 等错误响应。

优化

在闲鱼落地 Dubbo Mesh 的初期咱们走了一个“弯路”。

具体说来,最开始为了快速落地而采用了 Dubbo over HTTP 1.1/2 的模式,也即,将 Dubbo 协议封装在 HTTP 1.1/2 的消息体中完成服务调用。这一方案虽然能很好地享受 Envoy 已完整支持 HTTP 1.1/2 协议而带来的开发工做量少的好处,但性能测试代表其资源开销并不符合你们的预期。体现于,不只 Consumer 侧使用 mesh 后带来更高的 CPU 开销,Provider 侧也由于要提供经过 HTTP 1.1/2 进行调用的能力而致使多出 20% 的 CPU 开销且存在改造工做。最终,咱们回到让 Envoy 原生支持 Dubbo 协议的道路上来。

Envoy 支持 Dubbo 协议经历了两大阶段。第一个阶段 Envoy 与上游的通信并无采用单条长链接,使得 Provider 的 CPU 开销由于多链接而存在不可忽视的递增。第二个阶段则彻底采用单条长链接,经过多路复用的模式去除了前一阶段给 Provider 所带去的额外 CPU 开销。

Dubbo Mesh 在闲鱼预发环境上线进行性能与功能验证时,咱们意外地发现,Istio 原生 Pilot 的实现会将全量集群信息都推送给处于 Consumer 侧的 Envoy(Provider 侧没有这一问题),致使 Pilot 自身的 CPU 开销过大,而频繁的全量集群信息推送也使得 Envoy 不时会出现 CPU 负荷毛刺并遭受没有必要的内存开销。为此,咱们针对这一问题作了集群信息按需加载的重大改造,这一优化对于更大规模与范围下运用 Dubbo Mesh 具备很是重要的意义。优化的大体思路是:

  • Thin SDK 提供一个 API 供 Consumer 的应用在初始化时调用,周知其所需调用的服务列表。
  • Thin SDK 经过 HTTP API 将所依赖的服务列表告诉 Bonder,Bonder 将之保存到本地文件。
  • Envoy 启动时读取 Bonder 所保存的服务列表文件,将之看成元信息转给 Pilot。
  • Pilot 向 Nacos 只订阅服务列表中的集群信息更新消息且只将这些消息推送给 Envoy。

监控

可观测性(observability)是 Service Mesh 很是重要的内容,在服务调用链路上插入了 Envoy 的情形下,越发须要经过更强的监控措施去治理其上的全部微服务。Dubbo Mesh 的监控方案并无使用 Istio/Mixer 这样的设计,而是沿用了阿里巴巴集团内部的方式,即信息由各进程以日志的形式输出,而后经过日志采集程序将之送到指定的服务端进行后期加工并最终展现于控制台。目前 Dubbo Mesh 经过 EagleEye 去跟踪调用链,经过ARMS去展现其余的监控信息。

性能评估

为了评估 Dubbo Mesh 的性能可否知足闲鱼业务的须要,咱们设计了以下图所示的性能比对测试方案。

其中:

  • 测试机器是阿里巴巴集团生产环境中的 3 台 4 核 8G 内存的 Pouch 容器。
  • 蓝色方框表明的是进程。测试数据所有从部署了 DartServer 和 Envoy 两进程的测试机 2 上得到。
  • 性能数据分别在非 mesh(图中红色数据流)和 mesh(图中蓝色数据流)两个场景下得到。显然,Mesh 场景下的服务流量多了 Envoy 进程所带来的一跳。
  • DartServer 收到来自施压的 Loader 进程所发来的一个请求后,将发出 21 次到 Provider 进程的 RPC 调用。在评估 Dubbo Mesh 的性能时,这 21 次是串行发出的(下文列出的测试数据是在这一情形下收集的),实际闲鱼生产环境上线时考虑了进行并行发送去进一步下降总体调用时延(即使没有 mesh 时,闲鱼的业务也是这样实现的)。
  • Provider 进程端并无部署 Envoy 进程。这省去了初期引入 Dubbo Mesh 对 Provider 端的改形成本,下降了落地的工做量和难度。

设计测试方案时,咱们与闲鱼的同窗共创了如何回答打算运用 Dubbo Mesh 的业务方必定会问的问题,即“使用 Dubbo Mesh 后对 RT(Response Time)和 CPU 负荷的影响有多大”。背后的动机是,业务方但愿经过 RT 这一指标去了解 Dubbo Mesh 对用户体验的影响,基于 CPU 负荷的增加去掌握运用新技术所引起的成本。

面对这一问题一般的回答是“在某某 QPS 下,RT 增长了 x%,CPU 负荷增长了 y%”,但这样的回答若是不进行具体测试是没法给出的(会出现“鸡和蛋的问题”)。由于每一个业务的自然不一样使得一个完整请求的 RT 会存在很大的差异(从几毫秒到几百毫秒),而实现业务逻辑所需的计算量又最终决定了机器的 CPU 负荷水平。基于此,咱们设计的测试方案在于评估引入 Dubbo Mesh 后,每通过一跳 Envoy 所引入的 RT 和 CPU 增量。当这一数据出来后,业务方彻底能够基于本身业务的现有数据去计算出引入 Dubbo Mesh 后的而掌握大体的影响状况。

显然,背后的逻辑假设是“Envoy 对于每一个 Dubbo 服务调用的计算量是同样的”,事实也确实如此。

测试数据

如下是 Loader 发出的请求在并发度为 100 的情形下所采集的数据。

表中:

  • Envoy 的 QPS 是 Loader 的 21 倍,缘由在上面测试方案部分有交代。
  • “单跳”的数据是从“21 跳合计”直接除以 21 所得,其严谨性值得商榷,但用于初步评估仍具参考价值(有数据比没有数据强)。
  • “整机负荷”表明了在 mesh 场景下测试机器 2 上 DartServer 和 Envoy 两进程的 CPU 开销总和。测试代表,CPU 负荷高时 Envoy 带来的单跳 RT 增幅更大(好比表中 Loader 的 QPS 是 480 时)。给出整机负荷是为了提醒读者关注引入 mesh 前业务的正常单机水位,以便更为客观地评估运用 Dubbo Mesh 将带来的潜在影响。
  • “CPU 负荷增幅”是指 CPU 增长的幅度。因为测试机是 4 核的,因此整机的 CPU 负荷是 400。

从表中数据来看,随着机器总体负荷的增长“CPU 负荷增幅”在高段存在波动,这与 RT 在高段的持续增大存在相关,从 RT 在总体测试中彻底符合线性增加来看总体数据合理。固然, 后面值得深刻研究数据背后的隐藏技术细节以便深刻优化。

线上数据

Dubbo Mesh 正式生产环境上线后,咱们经过对上线先后的某接口的 RT 数据进行了全天的比对,以便大体掌握 mesh 化后的影响。2019-01-14 该接口全面切成了走 Dubbo Mesh,咱们取的是 2019-01-20 日的数据。

图中蓝色是 mesh 化后的 RT 表现(RT 均值 3.3),而橙色是 mesh 化前的 RT 表现(RT 均值 3.27,取的是 2019-01-13 的数据)。因为线上天天的环境都有所不一样,要作绝对的比较并不可能。但经过上面的比较不难看出,mesh 化先后对于总体 RT 的影响至关的小。当总体 RT 小于 5 毫秒是如此,若是总体 RT 是几10、几百毫秒则影响就更小。

为了帮助更全面地看待业务流量的波动特色,下面分别列出了两天非 mesh(2019-01-06 和 2019-01-13)和两天 mesh(2019-01-20 和 2019-01-23)的比对数据。

总之,生产环境上的数据表现与前面性能评估方案下所得到的测试数据能很好地吻合。

洞见

Dubbo Mesh 在闲鱼生产环境的落地实践让咱们收获了以下的洞见:

  • 服务发现的时效性是 Service Mesh 技术的首要关键。 以集群方式提供服务的情形下(这是分布式应用的常态),由于应用发布而致使集群中机器状态的变动如何及时准确地推送到数据平面是极具挑战的问题。对于阿里巴巴集团来讲,这是 Nacos 团队致力于解决的问题。开源版本的 Istio 可否在生产环境中运用于大规模分布式应用也首先取决于这一能力。频繁的集群信息推送,将给控制平面和数据平面都带去负荷扰动,如何经过技术手段控制好扰动是须要特别关注的,对于数据平面来讲编程语言的“肯定性”(好比,没有 VM、没有 GC)在其中将起到不可忽视的做用。
  • 数据平面的软件实现最大程度地减小内存分配与释放将显著地改善性能。有两大举措能够考虑:
  1. 逻辑与数据相分离。 以在 Envoy 中实现 Dubbo 协议为例,Envoy 每收到一个 RPC 请求都会动态地建立 fitler 去处理,一旦实现逻辑与数据相分离,filter 的建立对于每个 worker 线程有且只有一次,经过这一个 filter 去处理全部的 RPC 请求。
  2. 使用内存池。 Envoy 的实现中基本没有用到内存池,若是采用内存池对分配出来的各类 bufffer 经过链表进行缓存,这将省去大量的内存分配与释放而改善性能。再则,对于处理一个 RPC 请求而屡次分散分配的动做整合成集中一次性分配也是值得运用的优化技巧。
  • 数据平面的 runtime profiling 是关键技术。 Service Mesh 虽然对业务代码没有侵入性,但对服务流量具备侵入性,如何在出现业务毛刺的情形下,快速地经过 runtime profiling 去发现问题或自证清白是很是值得关注的点。

心得

一年不到的探索旅程,让团队更加笃定“借力开源,反哺开源”的发展思路。随着对 Istio 和 Envoy 实现细节的更多掌握,团队很强列地感觉到了走“站在巨人的肩膀上”发展的道路少走了不少弯路,除了快速跟进业界的发展步伐与思路,还将省下精力去作更有价值的事和创新。

此外,Istio 和 Envoy 两个开源项目的工程质量都很高,单元测试等质量保证手段是平常开发工做中的基础环节,而咱们也彻底采纳了这些实践。好比,内部搭建了 CI 环境、每次代码提交将自动触发单元测试、代码通过 code review 并完成单元测试才能入库、自动化性能测试等。

展望

在 2019 年接下来的日子,咱们将着手:

  • 与 Sentinel 团队造成协力,将 Sentinel 的能力归入到 Dubbo Mesh 中补全对 HTTP 和 Dubbo 协议的限流、降级和熔断能力。
  • 在阿里巴巴集团大范围 Kubernetes(Sigma 3.1)落地的背景下,与兄弟团队探索更加优雅的服务流量透明拦截技术方案。
  • 迎合 Serverless 的技术发展趋势,深化经过 Dubbo Mesh 更好地轻量化应用,以及基于 Dubbo Mesh 对服务流量的自然敏感性去更好地实现 auto-scaling。
  • 在产品的易用性和工程效率方面踏实进取。

将来,咱们将及时与读者分享阿里巴巴集团在 Service Mesh 这一新技术领域的探索成果,也期待与你们有更多的互动交流。

本文做者:至简,阿里巴巴中间件高级技术专家,是阿里巴巴集团 Service Mesh 方向的重要参与者和推进者。

关于 Dubbo Mesh 的首次公开分享

 

原文连接 更多技术干货 请关注阿里云云栖社区微信号 :yunqiinsight

相关文章
相关标签/搜索