一、引言
Service Mesh 是蚂蚁金服下一代架构的核心,经过了2年的沉淀,我们探索出了一套切实可行的方案并最终通过了双十一的考验。本文主要分享在当下『路口』,我们在产品设计上的思考和实践,希望能给大家带来一些启发。
二、为什么需要 Service Mesh?
2.1 微服务治理与业务逻辑解耦
在 Service Mesh 之前,微服务体系的玩法都是由中间件团队提供一个 SDK 给业务应用使用,在 SDK 中会集成各种服务治理的能力,如:服务发现、负载均衡、熔断限流、服务路由等。
在运行时,SDK 和业务应用的代码其实是混合在一个进程中运行的,耦合度非常高,这就带来了一系列的问题:
- 升级成本高
- 每次升级都需要业务应用修改 SDK 版本号,重新发布;
- 在业务飞速往前跑的时候,是不太愿意停下来做这些和自身业务目标不太相关的事情的;
- 版本碎片化严重
- 由于升级成本高,但中间件还是会向前发展,久而久之,就会导致线上 SDK 版本各不统一、能力参差不齐,造成很难统一治理;
- 中间件演进困难
- 由于版本碎片化严重,导致中间件向前演进过程中就需要在代码中兼容各种各样的老版本逻辑,戴着『枷锁』前行,无法实现快速迭代;
有了 Service Mesh 之后,我们就可以把 SDK 中的大部分能力从应用中剥离出来,拆解为独立进程,以 Sidecar 的模式部署。通过将服务治理能力下沉到基础设施,可以让业务更加专注于业务逻辑,中间件团队则更加专注于各种通用能力,真正实现独立演进,透明升级,提升整体效率。
2.2 异构系统统一治理
随着新技术的发展和人员更替,在同一家公司中往往会出现使用各种不同语言、不同框架的应用和服务,为了能够统一管控这些服务,以往的做法是为每种语言、每种框架都重新开发一套完整的 SDK,维护成本非常高,而且对中间件团队的人员结构也带来了很大的挑战。
有了 Service Mesh 之后,通过将主体的服务治理能力下沉到基础设施,多语言的支持就轻松很多了,只需要提供一个非常轻量的 SDK、甚至很多情况都不需要一个单独的 SDK,就可以方便地实现多语言、多协议的统一流量管控、监控等治理需求。
2.3 金融级网络安全
当前很多公司的微服务体系建设都建立在『内网可信』的假设之上,然而这个原则在当前大规模上云的背景下可能显得有点不合时宜,尤其是涉及到一些金融场景的时候。
通过 Service Mesh,我们可以更方便地实现应用的身份标识和访问控制,辅之以数据加密,就能实现全链路可信,从而使得服务可以运行于零信任网络中,提升整体安全水位。
三、在当下『路口』的思考
3.1 云原生方案?
正因为 Service Mesh 带来了上述种种的好处,所以这两年社区中对 Service Mesh 的关注度越来越高,也涌现出了很多优秀的 Service Mesh 产品,Istio 就是其中一款非常典型的标杆产品。
Istio 以其前瞻的设计结合云原生的概念,一出现就让人眼前一亮,心之向往。不过深入进去看了之后发现,在目前阶段要落地的话,还是存在一些 gap 的。
3.2 Greenfield vs Brownfield
在正式展开讨论之前,我们先来看一副漫画。
上面这幅漫画描绘了这样一个场景:
- 有两个工人在工作,其中一个在绿色的草地(Greenfield)上,另一个在棕色的土地(Brownfield)上;
- 在绿色草地上的工人对在棕色土地上的工人说:“如果你没有给自己挖这么深的坑,那么你也可以像我一样做一些很棒的新东西”;
- 然后在棕色土地上的工人回答道:“你倒是下来试试!”;
这是一幅很有意思的漫画,从表面上看我们可以认为在绿色草地上的工人是站着说话不腰疼,不过其实本质的原因还是两者所处的环境不同。
在一片未开发过的土地上施工确实是很舒服的,因为空间很大,也没有周遭各种限制,可以使用各种新技术、新理念,我们国家近几十年来的一些新区新城的建设就属于这类。而在一片已经开发过的土地上施工就大不一样了,周围环境会有各种限制,比如地下可能有各种管线,一不小心就挖断了,附近还有各种大楼,稍有不慎就可能把楼给挖塌了,所以做起事来就要非常小心,设计方案时也会受到各种约束,无法自由发挥。
对于软件工程,其实也是一样的,Greenfield 对应着全新的项目或新的系统,Brownfield 对应着成熟的项目或遗留系统。
我相信大部分程序员都是喜欢做全新的项目的,包括我自己也是一样。因为可以使用新的技术、新的框架,可以按照事物本来的样子去做系统设计,自由度很高。而在开发/维护一个成熟的项目时就不太一样了,一方面项目已经稳定运行,逻辑也非常复杂,所以无法很方便地换成新的技术、新的框架,在设计新功能时也会碍于已有的架构和代码实现做很多妥协,另一方面前人可能不知不觉挖了很多坑,稍有不慎就会掉进坑里,所以行事必须要非常小心,尤其是在做大的架构改变的时候。
3.3 现实场景
3.3.1 Brownfield 应用当道
在现实中,我们发现目前大部分的公司还没有走向云原生,或者还刚刚在开始探索,所以大量的应用其实还跑在非 k8s 的体系中,比如跑在虚拟机上或者是基于独立的服务注册中心构建微服务体系。
虽然确实有少量 Greenfield 应用已经在基于云原生来构建了,但现实是那些大量的 Brownfield 应用是公司业务的顶梁柱,承载着更大的业务价值,所以如何把它们纳入 Service Mesh 统一管控,从而带来更大的价值,也就成了更需要优先考虑的话题。
独立的服务注册中心
3.3.2 云原生方案离生产级尚有一定距离
另一方面,目前 Istio 在整体性能上还存在一些有待解决的点(引述小剑老师在蚂蚁金服 Service Mesh 深度实践中的观点):
- Mixer
- Mixer 的性能问题,一直都是 Istio 中最被人诟病的地方;
- 尤其在 Istio 1.1⁄1.2 版本之后引入了 Out-Of-Process Adapter,更是雪上加霜;
- 从落地的角度看,Mixer V1 糟糕至极的性能,已经是“生命无法承受之重”。对于一般规模的生产级落地而言,Mixer 性能已经是难于接受,更不要提大规模落地……
- Mixer V2 方案则给了社区希望:将 Mixer 合并进 Sidecar,引入 web assembly 进行 Adapter 扩展,这是我们期待的 Mixer 落地的正确姿势,是 Mixer 的未来,是 Mixer 的『诗和远方』。然而社区望穿秋水,但Mixer V2 迟迟未能启动,长期处于 In Review 状态,远水解不了近渴;
- Pilot
- Pilot 是一个被 Mixer 掩盖的重灾区:长期以来大家的性能关注点都在 Mixer,表现糟糕而且问题明显的Mixer 一直在吸引火力。但是当选择放弃 Mixer(典型如官方在 Istio 新版本中提供的关闭 Mixer 的配置开关)之后,Pilot 的性能问题也就很快浮出水面;
- 我们实践下来发现 Pilot 目前主要有两大问题:1)无法支撑海量数据 2)每次变化都会触发全量推送,性能较差;
3.4 当下『路口』我们该怎么走?
我们都非常笃信云原生就是未来,是我们的『诗和远方』,但是眼下的现实情况是一方面 Brownfield 应用当道,另一方面云原生的 Service Mesh 方案自身离生产级还有一定的距离,所以在当下这个『路口』我们该怎么走?
我们给出的答案是:
其实如前面所述,我们采用 Service Mesh 方案的初心是因为它的架构改变可以带来很多好处,如:服务治理与业务逻辑解耦、异构语言统一治理、金融级网络安全等,而且我们相信这些好处不管对 Greenfield 应用还是 Brownfield 应用都是非常需要的,甚至在现阶段对 Brownfield 应用产生的业务价值会远远大于 Greenfield 应用。
所以从『务实』的角度来看,我们首先还是要探索出一套现阶段切实可行的方案,不仅要支持 Greenfield 应用,更要能支持 Brownfield 应用,从而可以真正把 Service Mesh 落到实处,产生业务价值。
四、蚂蚁金服的产品实践
4.1 发展历程和落地规模
Service Mesh 在蚂蚁金服的发展历程,先后经历过如下几个阶段:
- 技术预研 阶段:2017年底开始调研并探索 Service Mesh 技术,并确定为未来发展方向。
- 技术探索 阶段:2018年初开始用 Golang 开发 Sidecar MOSN ,年中开源基于 Istio 的 SOFAMesh 。
- 小规模落地 阶段:2018年开始内部落地,第一批场景是替代 Java 语言之外的其他语言的客户端 SDK,之后开始内部小范围试点。
- 规模落地 阶段:2019年上半年,作为蚂蚁金服金融级云原生架构升级的主要内容之一,逐渐铺开到蚂蚁金服内部的业务应用,并平稳支撑了618大促。
- 对外输出 阶段:2019年9月,SOFAStack 双模微服务平台入驻阿里云开始公测,支持 SOFA, Dubbo 和 Spring Cloud 应用
- 全面大规模落地 阶段:2019年下半年,在蚂蚁金服内部的大促核心应用中全面铺开,落地规模非常庞大,而且最终如『丝般顺滑』地支撑了双十一大促。
在今年双十一,Service Mesh 覆盖了数百个交易核心链路应用,MOSN 注入的容器数量达到了数十万,双十一当天处理的 QPS 达到了几千万,平均处理响应时间<0.2 ms,MOSN 本身在大促中间完成了数十次的业务无感升级,达到了我们的预期,初步完成了基础设施和业务的第一步的分离,见证了 Mesh 化之后基础设施的迭代速度。
4.2 SOFAStack 双模微服务平台
我们的服务网格产品名是 SOFAStack 双模微服务平台,这里的『双模微服务』是指传统微服务和 Service Mesh 双剑合璧,即『基于 SDK 的传统微服务』可以和『基于 Sidecar 的 Service Mesh 微服务』实现下列目标:
- 互联互通:两个体系中的应用可以相互访问
- 平滑迁移:应用可以在两个体系中迁移,对于调用该应用的其他应用,做到透明无感知
- 异构演进:在互联互通和平滑迁移实现之后,我们就可以根据实际情况进行灵活的应用改造和架构演进
在控制面上,我们引入了 Pilot 实现配置的下发(如服务路由规则),在服务发现上保留了独立的 SOFA 服务注册中心。
在数据面上,我们使用了自研的 MOSN,不仅支持 SOFA 应用,同时也支持 Dubbo 和 Spring Cloud 应用。 在部署模式上,我们不仅支持容器/K8s,同时也支持虚拟机场景。
4.3 大规模场景下的服务发现
要在蚂蚁金服落地,首先一个需要考虑的就是如何支撑双十一这样的大规模场景。前面已经提到,目前 Pilot 本身在集群容量上比较有限,无法支撑海量数据,同时每次变化都会触发全量推送,无法应对大规模场景下的服务发现。
所以,我们的方案是保留独立的 SOFA 服务注册中心来支持千万级的服务实例信息和秒级推送,业务应用通过直连 Sidecar 来实现服务注册和发现。
4.4 流量劫持
Service Mesh 中另一个重要的话题就是如何实现流量劫持:使得业务应用的 Inbound 和 Outbound 服务请求都能够经过 Sidecar 处理。
区别于社区的 iptables 等流量劫持方案,我们的方案就显得比较简单直白了,以下图为例:
- 假设服务端运行在1.2.3.4这台机器上,监听20880端口,首先服务端会向自己的 Sidecar 发起服务注册请求,告知 Sidecar 需要注册的服务以及 IP + 端口(1.2.3.4:20880);
- 服务端的 Sidecar 会向 SOFA 服务注册中心发起服务注册请求,告知需要注册的服务以及 IP + 端口,不过这里需要注意的是注册上去的并不是业务应用的端口(20880),而是Sidecar自己监听的一个端口(例如:20881);
- 调用端向自己的 Sidecar 发起服务订阅请求,告知需要订阅的服务信息;
- 调用端的Sidecar向调用端推送服务地址,这里需要注意的是推送的IP是本机,端口是调用端的 Sidecar 监听的端口(例如:20882);
- 调用端的 Sidecar 会向 SOFA 服务注册中心发起服务订阅请求,告知需要订阅的服务信息;
- SOFA 服务注册中心向调用端的 Sidecar 推送服务地址(1.2.3.4:20881);
经过上述的服务发现过程,流量劫持就显得非常自然了:
- 调用端拿到的『服务端』地址是127.0.0.1:20882,所以就会向这个地址发起服务调用;
- 调用端的 Sidecar 接收到请求后,通过解析请求头,可以得知具体要调用的服务信息,然后获取之前从服务注册中心返回的地址后就可以发起真实的调用(1.2.3.4:20881);
- 服务端的 Sidecar 接收到请求后,经过一系列处理,最终会把请求发送给服务端(127.0.0.1:20880);
可能会有人问,为啥不采用 iptables 的方案呢?主要的原因是一方面 iptables 在规则配置较多时,性能下滑严重,另一个更为重要的方面是它的管控性和可观测性不好,出了问题比较难排查。
4.5 平滑迁移
平滑迁移可能是整个方案中最为重要的一个环节了,前面也提到,在目前任何一家公司都存在着大量的 Brownfield 应用,它们有些可能承载着公司最有价值的业务,稍有闪失就会给公司带来损失,有些可能是非常核心的应用,稍有抖动就会造成故障,所以对于 Service Mesh 这样一个大的架构改造,平滑迁移是一个必选项,同时还需要支持可灰度和可回滚。
得益于独立的服务注册中心,我们的平滑迁移方案也非常简单直白:
1.初始状态
以一个服务为例,初始有一个服务提供者,有一个服务调用者。
2.透明迁移调用方
在我们的方案中,对于先迁移调用方还是先迁移服务方没有任何要求,这里假设调用方希望先迁移到 Service Mesh 上,那么只要在调用方开启 Sidecar 的注入即可,服务方完全不感知调用方是否迁移了。所以调用方可以采用灰度的方式一台一台开启 Sidecar,如果有问题直接回滚即可。
3.透明迁移服务方
假设服务方希望先迁移到 Service Mesh 上,那么只要在服务方开启 Sidecar 的注入即可,调用方完全不感知服务方是否迁移了。所以服务方可以采用灰度的方式一台一台开启 Sidecar,如果有问题直接回滚即可。
4.终态
4.6 多协议支持
考虑到目前大部分用户的使用场景,除了 SOFA 应用,我们同时也支持 Dubbo 和 Spring Cloud 应用接入SOFAStack 双模微服务平台,提供统一的服务治理。多协议支持采用通用的 x-protocol,未来也可以方便地支持更多协议。
4.7 虚拟机支持
在云原生架构下,Sidecar 借助于 K8s 的 webhook/operator 机制可以方便地实现注入、升级等运维操作。然而大量系统还没有跑在 K8s 上,所以我们通过 agent 的模式来管理 Sidecar 进程,从而可以使 Service Mesh 能够帮助老架构下的应用完成服务化改造,并支持新架构和老架构下服务的统一管理。
4.8 产品易用性
在产品易用性上我们也做了不少工作,比如可以直接在界面上方便地设置服务路由规则、服务限流等,再也不用手工写 yaml 了:
也可以在界面上方便地查看服务拓扑和实时监控:
4.9 阿里云公测中
最后打一个小小的广告,SOFAStack 双模微服务平台现在在阿里云公测中,欢迎感兴趣的企业前来体验,https://www.aliyun.com/product/sofa。
五、展望未来
5.1 拥抱云原生
目前已经能非常清楚地看到整个行业在经历从云托管(Cloud Hosted)到云就绪(Cloud Ready)直至云原生(Cloud Native)的过程,所以前面也提到我们都非常笃信云原生就是未来,是我们的『诗和远方』,虽然眼下在落地过程中还存在一定的 gap,不过相信随着我们的持续投入,gap 会越来越小。
另外值得一提的是我们拥抱云原生其根本还在于降低资源成本,提升开发效率,享受生态红利,所以云原生本身不是目的,而是手段,切不可本末倒置了。
5.2 持续加强 Pilot 的能力
为了更好地拥抱云原生,后续我们也会和 Istio 社区共建,持续加强 Pilot 的能力。
而就在最近,在综合了过去一年多的思考和探索之后,蚂蚁金服和阿里集团的同事们共同提出了一套完整的解决方案,来融合控制平面和传统注册中心/配置中心,从而可以在保持协议标准化的同时,加强 Pilot 的能力,使其逐步向生产级靠拢。
(更多细节可以参考小剑老师的蚂蚁金服 Service Mesh 深度实践一文,在此就不再赘述了)
5.3 支持透明劫持
前面提到在蚂蚁金服的实践中是基于服务注册中心来实现流量劫持的,该方案不管是在性能、管控能力还是可观测性方面都是不错的选择,不过对应用存在一定的侵入性(需要引入一个轻量的注册中心 SDK)。
考虑到很多用户对性能要求没那么敏感,同时有大量遗留系统希望通过 Service Mesh 实现统一管控,所以后续我们也会支持透明劫持,同时在管控性和可观测性方面会做增强。
六、结语
基于『务实』的理念,Service Mesh 在蚂蚁金服经过了2年的沉淀,我们探索出了一套现阶段切实可行的方案并最终通过了双十一的考验。在这个过程中,我们也愈发体验到了 Service Mesh 带来的好处,例如 MOSN 在大促中间完成了数十次的业务无感升级,见证了 Mesh 化之后基础设施的迭代速度。
我们判断,未来 Service Mesh 会成为云原生下微服务的标准解决方案,所以我们也会持续加大对 Service Mesh 的投入,包括接下来蚂蚁金服将和阿里集团一起深度参与到 Istio 社区中去,和社区一起把 Istio 打造成 Service Mesh 的事实标准。
最后,也欢迎志同道合的伙伴加入我们,一起参与建设激动人心的下一代云原生架构!