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

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

本次分享将从以以下次序展开进行:git


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

在看蚂蚁金服的服务化架构以前咱们先从一个简单的服务化调用示例提及,下图是 SOFARPC 基本原理:github


                                                    图1. SOFARPC 基本原理

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

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


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

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


                                                       图3. LDC 架构示例

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


服务化痛点

中间件版本升级

在上面介绍背景时,有介绍到目前 LDC 架构下服务调用的复杂度,这些复杂度目前是直接体如今应用的代码中。对于业务同窗来说,一个应用的关注重点是如何实现业务逻辑,至于高可用、容灾等能力更可能是总体架构层面会考虑的点。应用内经过引入 RPC 的 jar 包便可得到 LDC 架构下服务调用各类能力的支撑,带来便利的同时也能够看到这种模式的缺点:性能优化


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

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


       
                                              图5. SDK 内不一样能力对应的依赖

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

每一年双 11 须要涉及到架构调整时:好比支持弹性架构,须要作不少中间件客户端的版本升级来支撑更优的架构,对于业务同窗来说,这些升级是很耗费精力的,拿 200 个核心应用举例,每一个应用升级中间件版本通过研发、测试、再到部署预发、灰度、生产等环境须要 5我的日的话,200 个核心应用中间件升级须要耗费 1000 人日,若是这部分时间能够节省出来,每一年架构升级能够节约大量人力资源。

跨语言通信

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


                                               图6. Java 与 NodeJS 互调

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


                                                          图7. 多语言场景

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


解决痛点

SDK 能力下沉

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

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


       
                                             图9. SDK 与 Sidecar 对应的依赖

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


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

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


落地架构

总体架构


                                                    图11. Mesh 落地架构

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

图中名词解析:

ConfigServer:配置中心,负责各类元数据配置、动态开关等

Registry:服务注册中心,负责 IDC 内服务发现

AntVip:类 DNS 解析的产品,可经过域名解析一组目标地址,用于跨 IDC 服务发现

MQ:消息中心服务端,用于收发消息

落地数据

                                                    图12. 落地 CPU 数据

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

下降打扰度

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

 
                                                          图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 的版本升级。


                                                  图14. SOFAMosn 平滑升级

因为 SOFAMosn 与应用是独立的 container,如上图描述,SOFAMosn 的升级是须要作到 Pod 内镜像的热替换,这种热替换能力必需要保障几点:

一、Pod 不会被重建,应用进程始终正常运行

二、镜像的替换不会影响运行中的流量

三、镜像替换后整个 Pod 描述须要进行更新

为了达成以上目标,咱们经过对 Kubernetes 的改造以及自定义 Operator 来完成以上升级的处理。处理流程以下:


                                          图15. SOFAMosn 平滑升级流程

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

下面咱们来看下 SOFAMosn 升级过程当中,如何保障流量无损:


图16. 正常流量走向

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


                                                  图17. 正常流量走向

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


                                                  图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。

极致性能优化

                                                     图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 启动速度

通信协议层优化,低版本协议针对性升级,下降解包成本

演进方向

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

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


                                                          图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

        

相关文章
相关标签/搜索