推荐文章 | Article
Istio在百度百亿级流量生产环境的研发实践
作者 李慧文
Service Mesh从诞生至今短短数年,就以席卷之势成为了云原生时代的通信设施标准,被奉为“下一代微服务”。然而由于像Istio这样Service Mesh中的佼佼者,其在对异构基础环境支持、私有协议支持、复杂流量调度策略、产品化和易用性、性能和可靠性等方面还存在诸多限制和缺陷,Service Mesh的落地一直以来都令人谈虎色变。
2021年QCon(北京)全球软件开发者大会上,百度 陈鹏 分享了结合Service Mesh在百度公司Feed、手机百度、百度地图等百亿量级流量的核心生产环境大规模落地的真实案例,分享了关于上述Service Mesh落地的诸多痛点问题的深入思考和实践经验。
以下是演讲内容整理,以飨读者。
决定业务有没有必要上Service Mesh,在什么程度上使用Service Mesh,最重要的依据是业务现状。所以今天我会先分享百度服务治理的现状,再分享百度在落地Istio时遇到的问题,以及百度是如何解决的。
百度的Service Mesh经历了三个阶段:内部探索、跟进探索、拥抱开源。
2013年,百度研发了独立的Sidecar和Proxy代理一些流量,这是Service Mesh在百度的萌芽;2016年,百度网盘大规模落地的UFC系统和现在Service Mesh的理念和架构功能已经非常相似了,也是用Proxy代理流量控制中心;2016年的9月份,Service Mesh的概念首次被提出后,百度立刻意识到了它会带来的变革。所以2017年,百度采用Go语言自研了一套Service Mesh系统—— BMesh。
与此同时,社区发展迅速。2018年的7月,Service Mesh的明星产品可用于生产环境的Istio 1.0版本发布了。面临这个情况,百度最终决定拥抱开源。因此2019年,百度研发了基于社区的Istio + Envoy的解决方案,目前已经大规模落地了。
为什么要引入Service Mesh?
Service Mesh主要可以解决三种问题:
第一,多语言技术栈能力不统一。百度内部的语言生态非常复杂,内部应用最广泛的框架是基于C++的bRPC,还用了Java的Spring Cloud生态、PHP的RAL框架、Go的GDP等。同时使用了多个语言,但各个框架的使用方式、配置方式以及服务治理的能力天然是不统一的,这必然会损害用户体验和后端能力。
第二,服务治理周期长。分布式的能力总和业务进程耦合在一起,所以无论是技术库的维护升级,还是调整策略,服务治理的周期都非常长,成本也非常高。
第三,服务产品能力非常弱。大部分服务都是以配置文件为主,没有接入配置中心,可视化能力非常弱,没有平台化或产品化的功能,如配置变更版本追溯的能力,审查、审计的能力等,用户体验很差。
Service Mesh进程隔离的特性,很好地解决了这些问题。很多公司都想落地Service Mesh,但是落地的过程却很不顺利。我们以Istio为例,看看Service Mesh在生产环境落地面临的问题。
Istio在生产环境落地面临的问题的百度解决方案
Istio在生产环境落地面临很多问题首先,Istio原生是为了弥补Kuber-Proxy流量调度上的缺陷而设计的,所以它在很多方面深度依赖Kubernetes,而大多数公司还没有完全迁移到Kubernetes上,这必然影响Istio的落地;其次,Istio只支持HTTP协议,但是很多公司使用的是内部私有协议,而且Istio支持的策略也很有限,因此Istio落地时,我们主要专门解决这些协议和策略的问题;最后,Istio的稳定性、性能、产品能力也会影响业务方的使用规模。
那么这些问题,百度是如何解决的呢?我们先看第一个问题,Istio对Kubernetes的深度依赖。
对Kubernetes的依赖问题
Istio对Kubernetes依赖分为三部分,第一部分是Sidecar的注入和管理。
Kubernetes的PaaS的可编程性和接口比较好,但是我们自己的PaaS或类似平台缺乏这样好的规范或接口,这样的话如何注入Sidecar呢?注入之后,如何大规模自动化管理Sidecar呢?面对这些问题,百度落地Istio时联合了内部的PaaS团队,进行了支持Sidecar模式的联动研发。
Istio对Kubernetes依赖的第二部分,是Istio的各类配置依赖了Kubernetes各种组件,尤其是依赖了API Server和etcd做流量调度策略的存储。API Server和etcd是可以进行独立部署的,所以百度保留了这部分组件。
最头疼的是第三个问题,Istio依赖于Kubernetes的服务和流量模型,比如说服务调用基于虚拟的ClusterIP,比如流量劫持使用了Iptables或IPVS。
由于一些性能稳定性、可管控性等等的原因,百度的生产环境是无法使用Iptables,内部的服务发现也没有用Kubernetes的方式,所以这个问题是最棘手的,决定了百度的流量到底能不能够让Mesh接管。面对这个问题,百度选择了研发新的流量劫持模式——基于Naming的流量劫持。
在传统的这种软硬件环境下如何做Mesh流量的接管
基于Naming的流量劫持
百度的流量劫持模式是基于百度微服务体系的私有Naming系统的。
图中左侧是Consumer,右侧是Provide。正常Consumer调用Provide时,会去注册中心或本地的Agent查找下游的服务实例列表。
接入Mesh以后,第一步,我们会在Mesh的上层用户产品—— Console上定义一个连接关系。图中定义的连接关系是Consumer会访问Provide。借鉴Kubernetes的ClusterIP的概念,我们会给它分配一个本地回环地址。图中举例的本地的回环地址是127.1.1.1,代表了访问的连接关系。
接着我们会把这个连接关系下发给Consumer侧的Sidecar,即代理Envoy。Envoy会监听127.1.1.1的地址,服务会监听另外的端口。
第三步我们会联动Envoy和Naming Agent。Envoy会把自己的监听的地址注册到Naming Agent里伪装自己。此时业务的Naming Lib去访问Naming Agent拿下游,拿到的是本地Envoy的地址。 图中Envoy把自己注册成了Provide,地址是127.1.1.1:8000,不是真实下游Provider的10.1.1.2:3000。
第四步Consumer会发出请求,而第五步返回的是127.1.1.1的8000端口。此时的核心思想是Envoy“欺骗”Naming Agent自己是下游的实例,把流量导到自己。Consumer以为它请求的是真正的Provide,实际上是把流量发给了本地的Envoy。Envoy收到以后,会去真正的Naming Agent里做解析。
这样可以实现在Sidecar侧做服务发现。这样做是因为策略配置变更频率低,而服务端点的这种实例状态信息的变化频率高,控制面做服务发现压力很大。
另外第7步里Envoy去请求下游时,Inbound的流量是可选的。图中既可以请求Provide真实监听的3000端口,也可以请求Envoy监听的3001端口。这样,出口流量必须经过Envoy,但是入口流量却不一定。
这是因为业务方会担心多过一次Envoy,会影响耗时和性能。而Envoy的能力,比如说负载均衡、超时、重试、熔断等都集中在上游,下游的功能很少,所以我们把下游做成了可选的模式。当然,如果你希望拥有Envoy全部功能,而且对性能不那么敏感的话,可以在Consumer和Provide侧都接入Sidecar。
原生Istio会给任何Sidecar推送全集群所有服务的信息,比如Consumer可能只需访问一个服务Provide,而Istio会给它所有服务的信息,这对Consumer自身的Sidecar资源开销和控制面推送的压力都很大。
而我们的方案定义了Link模型,这样可以做到精准下发,Consumer只会收到Provide相关的配置,XDS的推送量可以从O(N)降到O(1),Envoy的内存占用也会大幅度减少。
面对故障,我们在Envoy和Naming Agent之间设置了一个非常敏感的HeartBeat——心跳探活机制(上图中红色的部分)。一旦检测到Sidecar故障,我们会及时地去掉Envoy注册的伪装实例,Consumer服务会在下一次解析周期里近乎实时地回退到直连模式。因此业务方不必担心Envoy是否挂了。
因为Naming Lib适用范围很广,所以通过修改Naming Lib做流量劫持的方案适用范围也很广。而且在没有使用容器网络的主机网络下,我们通过收集由PaaS动态分配的端口,也可以使用这套方案。
融合Envoy和bRPC的性能优化
在毫秒级别的请求、资源紧张、CPU内存敏感的场景下,Envoy无法满足业务方的需求。所以我们基于bRPC和Envoy各自具有独到的优势,做了深度二次开发。
bRPC实现了一个非常高性能的用户态的线程,不完全等同于Go语言的协程,但是和用户态很相像,有高性能的IOBuf库,可以高效地做Socket处理。它还有优秀的IO机制,擅长处理长尾等等场景。
而Envoy的扩展机制非常灵活,在L3、L4、L7层都提供了很多Filter扩展机制;此外,Envoy本身也实现了非常多丰富的策略,再加上它有XDS协议,可以进行动态地配置分发。
我们融合了这两套系统的优点。我们使用bRPC的内核组件重构了Envoy。融合之后,平均延时和CPU开销大幅降低,效果如下图所示:
支持私有协议和高级策略
面对原生Istio不支持私有协议或一些高级策略的问题,百度也进行了相关优化。
因为Istio的扩展架构比较灵活,所以百度基于Istio + Envoy的扩展机制,全面支持了大多数私有协议,包括百度内部标准协议Baidu STD、一些比较老的Nshead、HTTP、Java生态的Dubbo协议等。
Istio每新增一种协议,都需要制定一种语法,描述该协议流量分发方式。百度把这些协议统一为了标准的协议框架,减少了很多的重复开发。真正在数据面做流量转发时,我们可以根据请求HEAD的特性做协议嗅探。
高级策略方面,百度在Envoy里做了加强版的BackupRequest——DynamicBP。
BackupRequest的核心是快速重试:在一个请求还没有回来时,就发出一个新的请求,优先使用先回来的请求结果。重试在很多场景下是高危的,而且在延时不太稳定的场景下,很难确定该在什么时候进行重试。
DynamicBP会动态计算一段时间间隔的超时比例,借此设置重试时间。比如说对超过99分位值的长尾Request,才进行BackupRequest。这能避免雪崩,更安全。
由于Mesh的控制面可以对网络行为进行动态地编程、修改配置、实施生效,服务治理效率会大幅提升。之前大规模的服务治理调整需要耗费半年时间,现在只需要几天,明显提升了故障容忍的可用性。
除此之外,百度实现了和测试、混沌相关的流量复制、流量镜像和一些其它高级负载均衡策略。这样业务方接入Mesh后,不仅能力不会变少,还获得了一些新的策略。线上实际效果如下图所示:
此外,Mesh与框架语言无关的特点可以赋能其它的框架和语言。所有框架和语言可以共享在Mesh里实现的策略。比如下图中的框架原先不具备某种高级的能力,所以前面抖动比较厉害,接入Mesh以后复用在Mesh里移植的能力,稳定性大幅度提升。
如何解决Istio原生产品能力缺失
Istio原生产品的能力本来就有缺失。比如CRD接口非常多,但是官方管理接口的Kiali基本上不可用;还有配置动态分发的安全问题,以前改配置有和PaaS结合的审计系统,接入Mesh后的监管问题。
面对这些问题,百度聚合了丰富的服务治理策略,可以让不了解Mesh的人,在良好的UI体验下完成服务治理。
一方面,百度集成了很多运维场景问题的解决方案,比如说跨机房切流,如何实时把流量切到其它机房,甚至按比例切流;再比如实时地关掉某一个链路的服务网格的开关;还有如何快速故障⽌损等等。
另一方面,如果Mesh上线后有任何问题,业务方可以一键回滚到对任何指定版本,及时地规避在线上遇到的问题。
当然,百度对任何一次服务变更都有详细的记录,会清晰地展示出操作者、操作时间、操作详情以及概述,便于审计或追查。
百度在Mesh上还做了很多平台化的工作。比如混沌平台可以和控制平面对接,负责调度任务,进行效果评估,而服务网格负责执行策略。图中App1调用App2边车时,需要注入一个延时故障或一个百分比故障验证特定的App2-3实例。这时混沌平台可以通过监控平台收集反馈指标。
再比如线上运维。线上运维最头疼的就是容量压测,直接压测可能会把服务压垮,所以常常需要在大半夜流量低时去压测,运维人员也会非常辛苦。有了Mesh以后,可以利用Mesh精准的动态分流能力,让容量压测平台对接Mesh。如下图所示,可以对下游某一个服务的实例,按百分比进行导流,让它接受比较大的流量。根据小部分实例的容量上限和实例的占比,就可以计算出服务在线上真实环境的容量水平。
百度智能云云原⽣微服务平台支持以上所有功能、协议扩展、性能优化,还支持公有云和私有化部署,感兴趣的同学可以去看一下。
百度Service Mesh落地经验总结
这里是一张百度Service Mesh的全景图,要想做Service Mesh落地,就要打通图中的所有环节。
当前百度使用Mesh的业务很多,包括手机百度/Feed、百度地图、小程序、好看视频等。切入Mesh的服务体量有几千个,实例数在10万左右,每天流量的PV是百亿级别。
通过接入Mesh,百度实现了跨语言统一的服务治理,提升了服务的可用性,微服务治理的周期从月级缩短到了分钟级。同时,服务变更的效率提升了10倍以上,再加上产品化、平台化等等的产品,运维人员的体验也明显提升了。
Istio落地的核心要素总共有四个方面:务实、性能、稳定性和体验。这四个方面中最重要的是务实,也就是必须要适配公司的基础设施,实现公司生产环境里使用的策略或协议。这决定了能不能接Mesh,后面三个方面不过是接入规模或体验的问题。
Istio社区关注的是透明、安全性、可观察性、可扩展性等特性,百度关注的是Istio落地时的性能、流量治理策略、Sidecar管理的可管控性、以及复杂网络或底层基础设施环境的支持。
未来,百度希望和社区继续融合,持续地跟进社区的新版本,引⼊社区⾼级扩展特性,同时百度也会向社区贡献性能优化和策略扩展相关的经验,和社区共建Istio生态。
嘉宾介绍
陈鹏,百度云原⽣技术专家,现负责百度Service Mesh的研发和落地,对服务网格以及云原生有深入研究。见证了百度Service Mesh从无到有,从摸索到大规模落地演变过程。致力于推动Service Mesh在多种场景下的落地。