作者简介
本文作者佐思、烧鱼、Shirley博,来自于携程Cloud Container团队,主要从事Service Mesh在携程的落地,负责控制面的可用性及优化建设,以及推进各类基础设施服务的云原生化。该团队负责K8s容器平台的研发和优化工作,专注于推动基础设施云原生架构升级,以及创新产品的研发和落地。
一、背景
为了支撑业务的高速发展,从17年开始,携程内部逐步推进应用容器化改造与业务上云工作,同期携程技术架构经历了从集中式单体应用到分布式微服务化的演进过程。
随着Kubernetes的不断发展和推广,服务网格(Service Mesh)在近几年也变得很流行。而 Servive Mesh 之所以越来越受欢迎,在提供更丰富的服务治理、安全性、可观测性等核心能力外,其从架构设计层面解决了以上几个痛点,服务治理能力以 Sidecar 的模式下沉到数据面,解决了 SDK 升级及多语言的问题,对于像负载均衡、熔断、限流等策略配置,由控制面统一管理和配置,并下发到数据面生效。在整体架构上云技术方案选型上,权衡各类方案的功能完备性、架构扩展性、改造维护成本及社区发展等,最终选择基于Istio构建Service Mesh平台治理方案。
1.1 携程Service Mesh发展
从2020年中,我们依托K8S底座能力,进行Service Mesh技术预研,深度定制Istio,并与携程框架部门合作进行了小规模的落地试点。2021年底,接入非核心应用600+,为Service Mesh在携程的最终落地奠定基础。到目前为止,生产环境已有2000个应用(业务POD数近1W)接入,预期下半年推进核心应用的接入。
1.2 携程Service Mesh数据表现
在前期应用接入过程中,针对Istio稳定性(主要在性能)方面,梳理了以下几个问题:
控制面并发性能:pilot对象处理的并发性能是否满足平台需求?
控制面配置下发时效性:配置下发的延迟及准确性是否能够满足业务需求?
本文主要分享在当前的体量下,回答上述问题,使控制面平稳支撑大规模 Sidecar 的落地,通过下述优化之后,测试域(Istio CR量级在1W+)如下图所示:
- 从实际生产来看,ServiceEntry的处理效率提升了15倍左右
- 从测试域来看,整体initContext时延从原先P99 30s左右到目前P99 5-10秒左右
- 从测试域来看,整体优化水平从原先P99 30s+到目前的P99 15s左右(该处为全量推送水平,其中15s的结果是平衡资源使用与推送效率调参的目标值,这里PILOT_DEBOUNCE_AFTER 设置为10s)
- 开启增量推送后,实例推送在测试域的推送效果从10-30s缩减至2.5s左右
携程目前Istio落地版本为1.10
二、Service Mesh优化的思路与挑战
2.1 现状
针对Service Mesh在携程落地的服务目标,可以用一句话进行总结:能够通过横向扩展,支撑万级业务服务。为了完成上述目标,团队面临以下挑战:
- 当前 Istio的对象处理性能等方面无法满足平台需求
- 配置下发的延迟及准确性无法满足业务需求
经过前中期,针对 Istio架构进行深入研究以及上线前期测试的性能预研,核心问题聚焦在以下几点:
- istio对象处理性能较低:在处理ServiceEntry时的并发性缺失及WorkloadEntry Selector模式的计算高耗时等
- istio配置推送性能较低:配置推送时对象的全量处理拉长下发时延,并会随着Istio对象增长而近线性增长
2.2 优化实践
接下来主要分享携程所经历过的性能问题,和对应的优化的方向:
对象处理性能
当前istio使用内部queue处理各类Object事件,其为线性处理流程,效率比较低下,为此社区提供namespace filter方式进行处理,以减缓性能问题,但针对Istio相关对象,未实现基于namespace的隔离,因此效率提升不太符合预期。
推送性能
xDS 是 istio 控制面和数据面 envoy 之间的通信协议,其中x 表示多种协议的集合,可以简单的把 xDS 理解为,网格内的服务发现数据和治理规则的集合。 xDS 数据量的大小和网格规模是正相关的。
当前 istio 下发 xDS 使用的是全量下发 策略,也就是网格里的所有 sidecar,内存里都会有整个网格内所有的服务发现数据。 在大量服务实例的情况下,全量下发会影响 Pilot 和 Sidecar 的性能和稳定性,虽然Istio 在不断的演进过程中引入了一些 scoping 的机制,就是 Sidecar 这个 CRD,这个配置可以显式的定义服务之间的依赖关系,但该scoping方案还是无法达到业务侧的推送延迟预期。
首先,简要介绍一下Istio推送的过程:
注:这里使用海东同学的推送源码分析图
根据上图结合源码可知:
- StreamAggregatedResources 会和当前的 Proxy 创建一个连接,并创建一个接受请求的 reqChannel 。同时开启一个新的协程 receiveThread 处理客户端主动发起的请求,期间调用 s.globalPushContext().InitContext(s.Env, nil, nil) 进行数据初始化,其中InitContext需要处理Istio 所有CR的全量数据(如VirtualServices、DestinationRules、EnvoyFilters和SidecarScopes等),该操作耗时较长,因测试环境上述对象量级在2w左右,导致执行耗时P99 在28s左右。
- 从 con.pushConnection 中获取到 pushEv 事件后,调用 s.pushConnection() 进行处理,判断是否为全量推送:
if pushRequest.Full {
// Update Proxy with current information.
s.updateProxy(con.proxy, pushRequest.Push)
}