蚂蚁金服 Service Mesh 落地实践与挑战

简介: 这篇文章介绍了蚂蚁金服在 Service Mesh 落地的演进过程以及相关痛点的解决方式,希望可以通过我们的实际经历来为大家带来一些思考.

本文整理自 GIAC(GLOBAL INTERNET ARCHITECTURE CONFERENCE)全球互联网架构大会,蚂蚁金服平台数据技术事业群技术专家石建伟(花名:卓与)的分享。分享基于 Service Mesh 的理念,结合蚂蚁金服内部实际场景,将中间件、数据层、安全层等能力从应用中剥离出来后下沉至独立的 Sidecar SOFAMosn 中,结合 Kubernetes 运维体系,提供应用无感知的情况下升级基础设施层能力的案例。

image.png

本次分享将从以如下次序展开进行:
image.png

蚂蚁金服当前的服务化现状

在看蚂蚁金服的服务化架构之前我们先从一个简单的服务化调用示例说起,下图是 SOFARPC 基本原理:
image.png
图1. SOFARPC 基本原理

我们从上图可以看出,构建一个服务化框架需要有服务注册中心,有服务定义,调用方和服务提供方使用相同的服务定义来互相通讯。通过服务注册中心,调用方可以直接订阅到服务提供方的地址,采用点对点的方式直接发起请求。客户端内可实现服务发现、路由寻址、负载均衡、限流熔断等能力来增强服务通讯能力。通过我们开源的 SOFARPC、SOFARegistry、SOFABoot,用户已经可以直接构建起微服务体系,助力业务发展。

蚂蚁金服发展至今,双 11 系统需要应对的交易洪峰逐年递增:

image.png
图2. 历年双 11 交易额与峰值数据

每秒 26.5 万笔交易是 2017 年双 11 的峰值数据,这个数据背后有非常复杂的架构支持,LDC 单元化架构是蚂蚁金服沉淀多年的核心架构,依靠这个架构实现每年峰值交易量飞速增长下系统依然能平滑渡过。我们来简要看下 LDC 架构:

image.png
图3. LDC 架构示例

上图摘自《金融级分布式架构》中的素描单元化一文,这里不详细展开。LDC 的单元化架构给应用的服务化带来更多的规范与抽象,服务路由中需要考虑单元间的调用,跨机房调用等更多场景。这里主要希望表达的是 LDC 架构给 RPC 调用带来更高的复杂度。

服务化痛点

中间件版本升级
在上面介绍背景时,有介绍到目前 LDC 架构下服务调用的复杂度,这些复杂度目前是直接体现在应用的代码中。对于业务同学来讲,一个应用的关注重点是如何实现业务逻辑,至于高可用、容灾等能力更多是整体架构层面会考虑的点。应用内通过引入 RPC 的 jar 包即可获得 LDC 架构下服务调用各种能力的支撑,带来便利的同时也可以看到这种模式的缺点:

image.png
图4. APP 业务与 SDK 组成部分

应用内除业务逻辑之外,由中间件的 SDK 引入大量外部依赖,来完成服务发现、路由寻址、负载均衡、限流熔断、序列化、通讯等能力,每个组件的引入都可能带来稳定性风险,以及更高的升级成本。

image.png
图5. SDK 内不同能力对应的依赖

根据目前 SOFARPC 在内部的版本举例,服务发现依赖 SOFARegistry 的客户端做 IDC 内的服务发现,依赖 Antvip 做跨 IDC 的服务发现,ZoneClient 集成 LDC 架构的单元化信息,路由寻址需要根据请求的入参计算目前 Zone 然后确定调用目标,限流熔断依赖 Guardian 组件,通讯协议与序列化协议相对稳定,变更较少。仅为了完成服务调用,应用需要额外引入 7+ 客户端包。

image.png

每年双 11 需要涉及到架构调整时:比如支持弹性架构,需要做很多中间件客户端的版本升级来支撑更优的架构,对于业务同学来讲,这些升级是很耗费精力的,拿 200 个核心应用举例,每个应用升级中间件版本经过研发、测试、再到部署预发、灰度、生产等环境需要 5个人日的话,200 个核心应用中间件升级需要耗费 1000 人日,如果这部分时间可以节省出来,每年架构升级可以节约大量人力资源。

跨语言通讯
蚂蚁金服发展至今,内部业务百花齐放,搜索推荐、人工智能、安全等各种业务使用到的技术栈非常多样化,跨语言的服务通讯能力也十分重要。早在几年前,Java 之外规模最大的就是 NodeJS 应用,为了让 Java 和 NodeJS 应用之间可以复用蚂蚁金服内部的各种中间件和基础设施,前端团队使用 NodeJS 逐步重写了各种中间件客户端,让整个 NodeJS 和 Java 体系可以完美互通。

image.png
图6. Java 与 NodeJS 互调

中间件 SDK 跨语言重写与维护成本极高,随着语言种类的增多,跨语言通讯的诉求也越来越多。

image.png
图7. 多语言场景

Java, NodeJS, Go, Python, C++ 等,5+ 语言,中间件 SDK 全部重写成本极高。这些问题不得不激励我们寻找更优的解法。

解决痛点

SDK 能力下沉
image.png
图8. SDK 瘦身并下沉能力至 Sidecar

依然以上述 RPC SDK 举例,SDK 中的能力我们可以根据稳定性与不可剥离等特性来看,哪些是可以从应用中抽出来的,尽量把 SDK 做薄,做的足够稳定无需变更,那么升级成本将不复存在。

image.png
图9. SDK 与 Sidecar 对应的依赖

RPC SDK 中的服务发现、路由寻址、限流熔断等特性,是更易于变更的,我们将这部分能力下沉至独立的 Sidecar 中,可以复用这部分能力,让多语言的 SDK 只实现最基本的序列化与通讯协议,而这些能力是很轻量且易于实现的。这里的 Sidecar 我们是希望它作为独立进程存在,和业务应用的进程剥离,并和业务应用的升级解耦开来,实现业务和基础设施并行发展,互不干扰的愿景。

image.png
图10. RPC 消息与数据源能力下沉

除了 RPC 通讯,我们还可以下沉消息、数据源等能力至 Sidecar 中,业务应用可以越来越薄,SDK 实现成本也降低到可接受的程度,基础设施层与业务剥离,双方均可独立演进。

落地架构

整体架构
image.png
图11. Mesh 落地架构

不同于开源的 Istio 体系,蚂蚁金服内部版 Service Mesh 落地优先考虑数据面的实现与落地,控制面在逐步建设中,整体的架构上看,我们使用数据面直接和内部的各种中间件服务端对接,来完成 RPC、消息等能力的下沉,给业务应用减负。由上图可以看出,我们将不同的 Sidecar 与业务应用编排在同一个 Pod 中,App 与 SOFAMosn 直接通讯,SOFAMosn 来负责目标接口的服务发现、路由寻址,并且由 SOFAMosn 内置的安全模块来做应用间调用的加密鉴权。通过 DBMesh 的 Sidecar 来实现数据层的下沉,App 不在需要与多个数据源建立连接,只需要连接本 Pod 内的 DBMesh 即可完成数据层调用,数据库的用户名、密码、分库分表规则等均不再需要关心。

图中名词解析:
• ConfigServer:配置中心,负责各种元数据配置、动态开关等
• Registry:服务注册中心,负责 IDC 内服务发现
• AntVip:类 DNS 解析的产品,可通过域名解析一组目标地址,用于跨 IDC 服务发现
• MQ:消息中心服务端,用于收发消息

落地数据
image.png
图12. 落地 CPU 数据

目前这套架构已经在支付核心链路中做试点,618 大促 Mesh 化应用对比无 Mesh 化应用 CPU 损耗增长 1.7%,单笔交易整体耗时增长 5ms。CPU 增长是由于多出一个进程,请求增加一条之后,RT 会有稳定的小幅增长,但这些成本相比于整体架构带来的红利,微乎其微,并且针对整个数据面的持续优化是有望逐步减少资源占用,提升资源利用率。

降低打扰度
中间件能力下沉在架构上看是可行的,实际落地如何做到无打扰的在奔跑的火车上换轮子,低打扰是一个非常重要的考量点。借助于 Kubernetes 的优秀实践,将业务容器与 Sidecar 容器编排在同一个 Pod 中是比较合理的架构,Sidecar 与业务容器互不干扰,互相升级均可做到双方无感。

image.png
图13. 落地方式

我们为了让业务应用升级尽可能如丝般顺滑,主要做了如下优化方案:
1.无感镜像化
蚂蚁金服内部还有部分应用未完成镜像化,或者说以富容器的方式来使用镜像化,这种方式也是在逐步淘汰的过程中,为了让业务更顺滑的镜像化,PAAS 平台联动整个研发体系,将应用的打包过程通过自动生成 Dockerfile 的方式主动帮用户完成镜像化。做到用户无感知镜像化改造。
2.低感 Mesh 化
镜像化完成之后,想要借助 Pod 模型将应用的容器和 SOFAMosn 的容器部署在一起,我们需要将底层资源管理与调度全部替换到 Kubernetes 体系。然后在 PAAS 上给 Mesh 化的应用增加标识,通过 Kubernetes 识别这些标识并主动注入 SOFAMosn sidecar 来完成应用的 Mesh 化接入。
3.无感 Sidecar 升级
Sidecar 与业务进程独立后,还有一个核心的诉求就是希望 Sidecar 可以独立升级,为了让 Sidecar 的升级尽量对生产做到无打扰,我们实现了 SOFAMosn 平滑升级的 Operator,通过对运行中 SOFAMosn 的连接迁移,实现整个升级过程应用完全无感知。当然这里面包含着很多挑战,后面我们会详细介绍。

落地挑战

Sidecar 平滑升级
目前我们已经实现 SOFAMosn 的平滑升级能力,SOFAMosn 的主要能力是 RPC 和 消息的通讯代理,平滑升级的目的是业务 App 进程不重启,业务请求不中断,完成 SOFAMosn 的版本升级。
image.png
图14. SOFAMosn 平滑升级

由于 SOFAMosn 与应用是独立的 container,如上图描述,SOFAMosn 的升级是需要做到 Pod 内镜像的热替换,这种热替换能力必须要保障几点:
1.Pod 不会被重建,应用进程始终正常运行
2.镜像的替换不会影响运行中的流量
3.镜像替换后整个 Pod 描述需要进行更新
为了达成以上目标,我们通过对 Kubernetes 的改造以及自定义 Operator 来完成以上升级的处理。处理流程如下:

image.png
图15. SOFAMosn 平滑升级流程

在不考虑多镜像间做平滑升级的场景下,通过 Fork 进程,可以继承父进程的 FD 来完成长连接的迁移,实现无损热升级。SOFAMosn 以镜像化的方式运行后,平滑升级的难度极大增加。整个平滑升级的难点在于如何让不同容器内的 SOFAMosn 进程可互相感知并可完成连接迁移。

下面我们来看下 SOFAMosn 升级过程中,如何保障流量无损:
image.png
图16. 正常流量走向

SOFAMosn 处理的正常流量分为入口流量和出口流量,Client 可以看成和 SOFAMosn 部署在同 Pod 内的 App,Server 可以是请求调用的目标服务提供方,可以是一个 App 也可以是被调用 App 侧的 SOFAMosn。当一笔请求从 Client 发至 Server 时,中间会经过两条长连接:TCP1 和 TCP2,SOFAMosn 会记录这笔请求对应的 ConnectionID,来完成请求的发起与响应。

image.png
图17. 正常流量走向

当新的 Mosn 容器被启动时,Mosn 会根据本地的 Domain Socket 来尝试发送请求,当另一个 Mosn 进程存在时,Mosn V1 和 Mosn V2 进入热升级模式,Mosn V1 会将已存在连接的 FD 和已读出的数据包 通过 Domain Socket 发送至 Mosn V2 同时 V1 将不会再从已迁移的 FD 中读取数据,FD 迁移完成所有流量将会直接由 Mosn V2 来处理。

image.png
图18. 逆向流量迁移

Mosn V1 和 Mosn V2 进入热升级模式之后,可能会存在 Mosn V1 已经将请求发给 Server 后 Server 还没有来得及响应的情况,这种场景 Mosn V1 在迁移 FD 给 Mosn V2 时,Mosn V2 会在 FD 接管到之后的 ConnectionID 返回给 Mosn V1,当 Mosn V1 收到 Server 返回的 Response 之后,会将这笔请求通过 Domain Socket 发送给 Mosn V2,然后 Mosn V2 根据 ConnectionId 即可找到 TCP1 的连接,然后响应给 Client。

极致性能优化
image.png
图19. 请求合并写

SOFAMosn 的核心网络模型是完全自实现的,我们在整个网络层做了非常多的优化,通过 golang 的 writev 我们把多笔请求合并成一次写,降低 sys.call 的调用,提升整体的性能与吞吐。同时在使用 writev 的过程中,有发现 golang 对 writev 的实现有 bug,会导致部分内存无法回收,我们给 golang 提交 PR 修复此问题,已被接受:https://github.com/golang/go/pull/32138

其他优化点还有很多,不再一一详细描述,仅供思路参考,如:
• SOFAMosn 日志异步化,避免磁盘问题对 SOFAMosn 转发性能的影响
• Route 路由结果缓存,空间换时间,提升吞吐
• 接近 90% 内存复用,尽量避免字节拷贝
• Cluster 懒加载,提升 SOFAMosn 启动速度
• 通讯协议层优化,低版本协议针对性升级,降低解包成本

演进方向

image.png
图20. 演进方向控制面结合

Service Mesh 的控制面建设我们也在规划中逐步向前推进,希望能统一数据面和控制面的交互模型,控制面尽量遵循 SMI 标准,增加对 TCP 协议的描述支持,逐步增强 SOFAMosn 作为数据面的稳定性,减少变更频率,用更通用的模型来描述服务发现、服务治理等场景,DBMesh 也会基于 XDS 做配置的下发,统一又控制面收口数据下发通道。这里控制面直接对接中间件的服务端是基于性能与容量考虑,蚂蚁金服内部的服务发现数据达单机房千万级别,使用 Kubernetes 的 ETCD 无法承载如此巨大的数据量,需要又控制面做桥梁并分片服务于不同的数据面。

image.png
图21. 产品化模型

接下来还会有完整的产品层建设,借助于 Mesh 化架构的思想,更多的能力希望通过下沉至 Sidecar 的方式来拿到架构升级带来的红利。Mesh 的产品层将会包括多种 Mesh 数据面形态的 Metrics 采集、监控大盘,控制面的统一对外途径,屏蔽外部系统与 Mesh 的交互复杂度,统一控制面与数据面交互协议,通过完善的运维体系建设,提升 Mesh 模式下的 Sidecar 灰度升级能力,做到对应用无打扰且稳定无人值守即可完成版本升级的目的。

总结

总结一下全文在 Service Mesh 领域的落地实践,可以归纳为以下六点:
• 应用层与基础设施层分离
• 基础设置层一次编写多处复用
• 数据面通过能力平移优先落地
• 降低打扰度提升落地效率
• 控制面建设统一数据面配置模型
• 性能、稳定性、可观测性持续优化

本文介绍了蚂蚁金服在 Service Mesh 落地的演进过程以及相关痛点的解决方式,希望可以通过我们的实际经历来为读者带来一些不同与社区主流方案的演进思考。

提到的相关开源组件地址:
• SOFAMosn:https://github.com/sofastack/sofa-mosn
• SOFARPC:https://github.com/sofastack/sofa-rpc
• SOFARegistry:https://github.com/sofastack/sofa-registry
• SOFABoot:https://github.com/sofastack/sofa-boot

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
7月前
|
存储 关系型数据库 MySQL
吃透 OceanBase:从底层原理到 Java 生产级落地全指南
本文详解OceanBase V4.4.2核心架构与实战:涵盖Shared-Nothing分布式设计、LSM-Tree存储引擎、Multi-Paxos强一致机制;深度对比MySQL兼容性;提供SpringBoot+MyBatis-Plus全栈Java示例,含Docker部署、分表建模、分布式事务及HTAP实战,并总结生产优化与避坑指南。(239字)
1124 2
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
510 27
|
数据采集 前端开发 API
React - 实现一个基于 Antd 的数值范围组件
这篇文章介绍了如何实现一个基于Ant Design的数值范围组件,以满足数据采集流程中表单数据的录入需求。文章详细说明了组件的设计思路、代码结构、使用方式以及参数说明,并提供了效果预览和注意事项。组件支持只能输入数字,具有自定义表单控件封装的特点,同时支持所有InputNumber属性,以适应不同业务场景的需求。
427 0
React - 实现一个基于 Antd 的数值范围组件
|
存储 运维 容灾
容灾的架构分析和容灾选择策略
容灾的架构分析和容灾选择策略
容灾的架构分析和容灾选择策略
|
9月前
|
存储 监控 Java
Sentinel工作原理
Sentinel 是面向分布式服务架构的流量治理组件,以“资源”为核心,通过流量控制、熔断降级、系统负载保护等规则保障系统稳定。其采用插槽链(Slot Chain)机制,支持灵活扩展,实现多维度运行时监控与防护,助力系统在高并发下平稳运行。
|
11月前
|
缓存 Cloud Native 中间件
《聊聊分布式》从单体到分布式:电商系统架构演进之路
本文系统阐述了电商平台从单体到分布式架构的演进历程,剖析了单体架构的局限性与分布式架构的优势,结合淘宝、京东等真实案例,深入探讨了服务拆分、数据库分片、中间件体系等关键技术实践,并总结了渐进式迁移策略与核心经验,为大型应用架构升级提供了全面参考。
Java程序员必学:JVM架构完全解读
Java 虚拟机(JVM)是 Java 编程的核心,深入理解其架构对开发者意义重大。本文详细解读 JVM 架构,涵盖类加载器子系统、运行时数据区等核心组件,剖析类加载机制,包括加载阶段、双亲委派模型等内容。阐述内存管理原理,介绍垃圾回收算法与常见回收器,并结合案例讲解调优策略。还分享 JVM 性能瓶颈识别与调优方法,分析 Java 语言特性对性能的影响,给出数据结构选择、I/O 操作及并发同步处理的优化技巧,同时探讨 JVM 安全模型与错误处理机制,助力开发者提升编程能力与程序性能。
Java程序员必学:JVM架构完全解读
|
存储 容灾 关系型数据库
OceanBase 高可用性架构解析
【8月更文第31天】在大数据和云计算蓬勃发展的今天,数据库作为数据存储的核心组件,其稳定性和可靠性直接影响到整个系统的性能。OceanBase 是由阿里巴巴集团自主研发的一款分布式关系型数据库系统,旨在为大规模在线交易处理(OLTP)场景提供高性能、高可用性的解决方案。本文将深入探讨 OceanBase 是如何通过其独特的架构设计来确保数据的高可用性和容灾能力。
845 0
|
算法 安全 数据安全/隐私保护
加密和解密数据
【10月更文挑战第6天】加密和解密数据
561 2