蚂蚁金服很早开始关注 Service Mesh,并在 2018 年发起 ServiceMesher 社区,目前已有 4000+ 开发者在社区活跃。在技术应用层面,Service Mesh 的场景已经渡过探索期,今年已经全面进入深水区探索。git
2019 年的双十一是咱们的重要时刻,咱们进行了大规模的落地。做为技术人能面对世界级的流量挑战,是很是紧张和兴奋的。当 Service Mesh 遇到双十一又会迸发出怎样的火花?蚂蚁金服的 LDC 架构继续演进的过程当中,Service Mesh 要承载起哪方面的责任?让咱们一块儿来揭秘蚂蚁金服 Service Mesh 双十一实战。github
Istio 清晰的描述了 Service Mesh 最核心的两个概念:数据面与控制面。数据面负责作网络代理,在服务请求的链路上作一层拦截与转发,能够在链路中作服务路由、链路加密、服务鉴权等,控制面负责作服务发现、服务路由管理、请求度量(放在控制面颇受争议)等。golang
Service Mesh 带来的好处再也不赘述,咱们来看下蚂蚁金服的数据面和控制面产品:算法
数据面:SOFAMosn。蚂蚁金服使用 Golang 研发的高性能网络代理,做为 Service Mesh 的数据面,承载了蚂蚁金服双十一海量的核心应用流量。后端
控制面:SOFAMesh。Istio 改造版,落地过程当中精简为 Pilot 和 Citadel,Mixer 直接集成在数据面中避免多一跳的开销。安全
今年,蚂蚁金服的核心应用全面接入 SOFAMosn,生产 Mesh 化容器几十万台,双十一峰值 SOFAMosn 承载数据规模数千万 QPS,SOFAMosn 转发平均处理耗时 0.2ms。性能优化
双十一落地数据服务器
在如此大规模的接入场景下,咱们面对的是极端复杂的场景,同时须要多方全力合做,更要保障数据面的性能稳定性知足大促诉求,整个过程极具挑战。网络
同时,Service Mesh 的落地也是一个跨团队合做的典范案例,集合了核心、RPC、消息、无线网关、控制面、安全、运维、测试等团队的精诚合做,接下来咱们会按照以上几个模块来解析 Service Mesh 的双十一落地状况,更多解析关注本语雀。架构
本文为《蚂蚁金服 Service Mesh 落地实践系列》第一篇 - 核心篇,做者:田阳(花名:烈元),蚂蚁金服技术专家,专一于高性能网络服务器研发,Tengine 开源项目核心成员,蚂蚁金服开源 SOFAMosn 项目核心成员。
SOFAMosn 主要划分为以下模块,包括了网络代理具有的基础能力,也包含了 XDS 等云原生能力。
SOFAMosn 做为底层的高性能安全网络代理,支撑了 RPC,MSG,GATEWAY 等业务场景。
SOFAMosn 支持两种 IO 模型,一个是 Golang 经典模型,goroutine-per-connection;一个是 RawEpoll 模型,也就是 Reactor 模式,I/O 多路复用(I/O multiplexing) + 非阻塞 I/O(non-blocking I/O)的模式。
在蚂蚁金服内部的落地场景,链接数不是瓶颈,都在几千或者上万的量级,咱们选择了 Golang 经典模型。而对于接入层和网关有大量长连接的场景,更加适合于 RawEpoll 模型。
一条 TCP 链接对应一个 Read 协程,执行收包,协议解析;
一个请求对应一个 worker 协程,执行业务处理,proxy 和 Write 逻辑;
常规模型一个 TCP 链接将有 Read/Write 两个协程,咱们取消了单独的 Write 协程,让 workerpool 工做协程代替,减小了调度延迟和内存占用。
协议扩展
SOFAMosn 经过使用同一的编解码引擎以及编/解码器核心接口,提供协议的 plugin 机制,包括支持:
SOFARPC;
HTTP1.x/HTTP2.0;
Dubbo;
NetworkFilter 扩展
SOFAMosn 经过提供 network filter 注册机制以及统一的 packet read/write filter 接口,实现了 Network filter 扩展机制,当前支持:
TCP proxy;
Fault injection;
StreamFilter 扩展
SOFAMosn 经过提供 stream filter 注册机制以及统一的 stream send/receive filter 接口,实现了 Stream filter 扩展机制,包括支持:
流量镜像;
RBAC鉴权;
做为金融科技公司,资金安全是最重要的一环,链路加密又是其中最基础的能力,在 TLS 安全链路上咱们进行了大量的调研测试。
经过测试,原生的 Go 的 TLS 通过了大量的汇编优化,在性能上是 Nginx(OpenSSL)的80%,Boring 版本的 Go(使用 cgo 调用 BoringSSL) 由于 cgo 的性能问题, 并不占优点,因此咱们最后选型原生 Go 的 TLS,相信 Go Runtime 团队后续会有更多的优化,咱们也会有一些优化计划。
go 在 RSA 上没有太多优化,go-boring(CGO)的能力是 go 的1倍;
p256 在 go 上有汇编优化,ECDSA 优于go-boring;
在 AES-GCM 对称加密上,go 的能力是 go-boring 的20倍;
在 SHA、MD 等 HASH 算法也有对应的汇编优化;
为了知足金融场景的安全合规,咱们同时也对国产密码进行了开发支持,这个是 Go Runtime 所没有的。虽然目前的性能相比国际标准 AES-GCM 仍是有一些差距,大概是 50%,可是咱们已经有了后续的一些优化计划,敬请期待。
为了让 SOFAMosn 的发布对应用无感知,咱们调研开发了平滑升级方案,相似 Nginx 的二进制热升级能力,可是有个最大的区别就是 SOFAMosn 老进程的链接不会断,而是迁移给新的进程,包括底层的 socket FD 和上层的应用数据,保证整个二进制发布过程当中业务不受损,对业务无感知。除了支持 SOFARPC、Dubbo、消息等协议,咱们还支持 TLS 加密链路的迁移。
容器升级
基于容器平滑升级 SOFAMosn 给了咱们不少挑战,咱们会先注入一个新的 SOFAMosn,而后他会经过共享卷的 UnixSocket 去检查是否存在老的 SOFAMosn,若是存在就和老的 SOFAMosn 进行链接迁移,而后老的 SOFAMosn 退出。这一块的细节较多,涉及 SOFAMosn 自身和 Operator 的交互。
SOFAMosn 的链接迁移
链接迁移的核心主要是内核 Socket 的迁移和应用数据的迁移,链接不断,对用户无感知。
SOFAMosn 的 metric 迁移
咱们使用了共享内存来共享新老进程的 metric 数据,保证在迁移的过程当中 metric 数据也是正确的。
基于 sync.Pool;
slice 复用使用 slab 细粒度,提升复用率;
经常使用结构体复用;
线上复用率能够达到90%以上,固然 sync.Pool 并非银弹,也有本身的一些问题,可是随着 Runtime 对 sync.Pool 的持续优化,好比 go1.13 就使用 lock-free 结构减小锁竞争和增长了 victim cache 机制,之后会愈来愈完善。
支持云原生统一数据面 API,全动态配置更新。
在上线前的准备过程当中,咱们在灰度环境针对核心收银台应用进行了大量的压测和优化,为后面的落地打下了坚实的基础。
从线下环境到灰度环境,咱们遇到了不少线下没有的大规模场景,好比单实例数万后端节点,数千路由规则,不只占用内存,对路由匹配效率也有很大影响,好比海量高频的服务发布注册也对性能和稳定性有很大挑战。
整个压测优化过程历时五个月,从最初的 CPU 总体增长20%,RT 每跳增长 0.8ms, 到最后 CPU 总体增长 6%,RT 每跳增长了 0.2ms,内存占用峰值优化为以前的 1/10 。
总体增长CPU 每跳RT 内存占用峰值
优化前 20% 0.8ms 2365M
优化后 6% 0.2ms 253M
部分优化措施
在 618 大促时,咱们上线了部分核心链路应用,CPU 损耗最多增长 1.7%,有些应用因为逻辑从 Java 迁移到 Go,CPU 损耗还下降了,有 8% 左右。延迟方面平均每跳增长 0.17ms,两个合并部署系统全链路增长 5~6ms,有 7% 左右的损耗。
在后面单机房上线 SOFAMosn,在全链路压测下,SOFAMosn 的总体性能表现更好,好比交易付款带 SOFAMosn 比不带 SOFAMosn 的 RT 还下降了 7.5%。
SOFAMosn 作的大量核心优化和 Route Cache 等业务逻辑优化的下沉,更快带来了架构的红利。
版本的升级都须要作一系列测试,新版本并非都最适合你的场景。咱们项目最开始使用的 Go 1.9.2,在通过一年迭代以后,咱们开始调研当时 Go 的最新版 1.12.6,咱们测试验证了新版不少好的优化,也修改了内存回收的默认策略,更好的知足咱们的项目需求。
GC 优化,减小长尾请求
新版的自我抢占(self-preempt)机制,将耗时较长 GC 标记过程打散,来换取更为平滑的GC表现,减小对业务的延迟影响。
https://go-review.googlesource.com/c/go/+/68574/
https://go-review.googlesource.com/c/go/+/68573/
Go 1.9.2
Go 1.12.6
内存回收策略
在 Go1.12,修改了内存回收策略,从默认的 MADV_DONTNEED 修改成了 MADV_FREE,虽然是一个性能优化,可是在实际使用中,经过测试并无大的性能提高,可是却占用了更多的内存,对监控和问题判断有很大的干扰,咱们经过 GODEBUG=madvdontneed=1 恢复为以前的策略,而后在 issue 里面也有相关讨论,后续版本可能也会改动这个值。
runtime: use MADV_FREE on Linux if available
使用 Go1.12 默认的 MADV_FREE 策略 ,Inuse 43M, 可是 Idle 却有 600M,一直不能释放。
在前期灰度验证时,SOFAMosn 线上出现了较严重的内存泄露,一天泄露了1G 内存,最终排查是 Go Runtime 的 Writev 实现存在缺陷,致使 slice 的内存地址被底层引用,GC 不能释放。
咱们给 Go 官方提交了 Bugfix,已合入 Go 1.13最新版。
internal/poll: avoid memory leak in Writev
SOFAMosn 在蚂蚁金服经历了双十一的大考,后续咱们还有更多的技术演进和支撑场景,欢迎有兴趣的同窗加入咱们。
SOFAMosn:https://github.com/sofastack/sofa-mosn
更多关于蚂蚁金服 Service Mesh 的双十一落地状况解析,请继续关注哟~