关于腾讯云:深入了解服务网格数据平面性能和调优

45次阅读

共计 7869 个字符,预计需要花费 20 分钟才能阅读完成。

在腾讯,曾经有很多产品已应用或者正在尝试应用 istio 来作为其微服务治理的根底平台。不过在应用 istio 时,也有一些对通信性能要求较高的业务会对 istio 的性能有一些担心。因为 envoy sidecar 的引入,使两个微服务之间的通信门路变长,导致服务延时受到了一些影响,istio 社区始终以来也有这方面的声音。基于这类埋怨,咱们心愿可能对这一通信过程进行优化,以更好的满足更多客户的需要。

首先,咱们看一下 istio 数据面的通信模型,来剖析一下为什么会对延时有这么大的影响。能够看到,相比于服务之间间接通信,在引入 istio 之后,通信门路会有明显增加,次要包含多出了两次本地过程之间的 tcp 连贯通信和用户态网络代理 envoy 对数据的解决。所以咱们的优化也分为了两局部进行。

内核态转发优化

那么对于本地过程之间的通信优化,咱们能做些什么呢?
其实在开源社区曾经有了这方面的摸索了。istio 官网社区在 2019 年 1 月的时候曾经有了这方面探讨,在文档外面提到了应用 ebpf 的技术来做 socket 转发的数据代理,使数据在 socket 层进行转发,而不须要再往下通过更底层的 TCP/IP 协定栈的一个解决,从而缩小它在数据链路上的通信链路长度。

另外,网络开源我的项目 cilium 也在这方面有一个比拟深刻的实际,同样也是应用了 ebpf 的技术。不过在 cilium 中本地网络减速只是其中的一个模块,没有作为一个独立的服务进行开发实际,在腾讯云外部没法间接应用,这也促使了咱们开发一个无依赖的解决方案。

当然在初期的时候,咱们也对 ebpf 的技术进行了一个验证,从验证后果中能够看到,在应用了 ebpf 的技术之后,它的延时大略有 20% 到 30% 的晋升,阐明 ebpf 的技术利用在本地通信上还是有肯定优化能力的。

简略介绍一下 ebpf,看一下它是怎么做到减速本地通信的。首先 ebpf 能够看作是一个运行在内核外面的虚拟机,用户编写的 ebpf 程序能够被加载到内核外面进行执行。内核的一个 verify 组件会保障用户的 ebpf 程序不会引发内核的 crash,也就是能够保障用户的 ebpf 程序是平安的。目前 ebpf 程序次要用来追踪内核的函数调用以及平安等方面。下图能够看到,ebpf 能够用在很多内核子系统当中做很多的调用追踪。

另外一个比拟重要的性能,就是咱们在性能优化的时候应用到的在网络上的一个能力,也就是上面提到的 sockhash。sockhash 自身是一个 ebpf 非凡的一个 kv 存储构造,次要被用作内核的一个 socket 层的代理。它的 key 是用户自定义的,而 value 是比拟非凡的,它存储的 value 是内核外面一个 socket 对象。存储在 sockhash 中的 socket 在发送数据的时候,如果可能通过咱们挂在 sockhash 当中的一个 ebpf 当中的程序找到接管方的 socket,那么内核就能够帮忙咱们把发送端的数据间接拷贝到接收端 socket 的一个接管队列当中,从而能够跳过数据在更底层的解决,比方 TCP/IP 协定栈的解决。

在 sidecar 中,socket 是怎么被辨认并存储在 sockhash 当中来实现一个数据拷贝的呢?咱们须要剖析一下数据链的本地通信的流量特色。

首先从 ingress 来讲,ingress 端的通信会比较简单一点,都是一个本地地址的通信。ingress 端的 envoy 过程和用户服务过程之间通信,它的原地址和目标地址刚好是一一对应的。所以咱们能够利用这个地址的四元组结构它的 key,把它存储到 sockhash 当中。在发送数据的时候,依据这个地址信息反向结构这个 key,从 sockhash 当中拿到接收端的 socket 返回给内核,这样内核就能够帮咱们将这个数据间接拷贝给接收端的 socket。

egress 会略微简单一点,在一个 egress 端服务程序对外收回的申请被 iptables 规定重定向到了 envoy 监听的一个 15001 的端口。在这里,发起方的源地址和接管方的目标地址是一一对应的,然而发起方的目标地址和接收端的源地址有了一个变动,次要是因为 iptables 对地址有一个重写。所以咱们在存储到 sockhash 中的时候,须要对这部分信息进行一个解决。因为 istio 的特殊性,间接能够把它改写成 envoy 所监听的一个本地服务地址。这样再存储到 sockhash 当中,它们的地址信息还是能够反向一一对应的。所以在查找的时候,还是能够依据一端的 socket 地址信息查找到另一端的 socket,达到数据拷贝的目标。

通过对 ebpf 减速原理的剖析,咱们开发进去一个 ebpf 的插件,这个插件能够不依赖于集群自身的网络模式,应用 daemonset 形式部署到 k8s 集群的各个节点上。其中的通信成果如下图所示,本地过程的一个通信在 socket 层间接被 ebpf 拦挡当前,就不会再往下发送到 TCPIP 协定栈了,间接在 socket 层就进行了一个数据拷贝,缩小了数据链路上的一个解决流程

上面是对成果的一个测试,从整体来看,它的延时有大略 5 到 8% 的延时晋升,其实晋升的幅度不是很大,次要起因其实在整个通信的流程当中,内核态的一个解决占整个通信解决的工夫,延时其实是比拟少的一部分,所以它的晋升不是特地显著。

另外 ebpf 还有一些缺点,比方它对内核版本的要求是在 4.18 版本之后才有 sockhash 这个个性。另外 sockhash 自身还有一些 bug,咱们在测试当中也发现了一些 bug,并且把它提交到社区进行解决。

Envoy 性能钻研与优化

后面介绍了对 istio 数据面对流量在内核的解决所进行的一些优化。在 istio 数据面的性能问题上,社区留神到比拟多的是在内核态有一个显著的转发流程比拟长的问题,因而提出了应用 eBPF 进行优化的计划,然而在 Envoy 下面没有太多的声音。尽管 Envoy 自身是一个高性能的网络代理,但咱们还是无奈确认 Envoy 自身的损耗是否对性能造成了影响,所以咱们就兵分两路,同时在 Envoy 下面进行了一些钻研。

首先什么是 Envoy?Envoy 是为分布式环境而生的高性能网络代理,能够说基本上是作为服务网格的通用数据立体被设计进去的。Envoy 提供不同层级的 filter 架构,如 listenerFilter、networkFilter 以及 HTTPFilter,这使 envoy 具备十分好的可扩展性。Envoy 还具备很好的可察看性,内置有 stats、tracing、logging 这些子系统,能够让咱们更容易地对系统进行监控。

进行 istio 数据面优化的时候,咱们面对的第一个问题是 Envoy 在 istio 数据面中给音讯转发减少了多少延时?Envoy 自身提供的内置指标是很难反映 Envoy 自身的性能。因而,咱们通过批改 Envoy 源码,在 Envoy 解决音讯的开始与完结的地位进行打点,记录时间戳,能够取得 Envoy 解决音讯的延时数据。Envoy 是多线程架构,在打点时咱们思考了性能和线程平安问题:如何高效而又精确地记录所有音讯的解决延时,以不便后续的进行剖析?这是通过如下办法做到的:

a. 给压测音讯调配惟一数字 ID;

b. 在 Envoy 中预调配一块内存用于保留打点数据,其数据类型是一个构造体数组,每个元素都是同一条音讯的打点数据;

c. 提取音讯中的数字 ID 当作工夫戳记录的下标,将工夫戳记录到预调配的内存的固定地位。通过这种形式,咱们平安高效地实现了 Envoy 内的打点记录(毛病是须要批改 Envoy 以及压测工具)。

通过离线剖析,咱们发现了 Envoy 内音讯解决延时的一些散布特色。左图是对 Envoy 解决延时与音讯数量分布图,横轴是延时,纵轴是音讯数量。能够看到在高延时部份,音讯数量有异样减少的景象,这不是典型的幂率散布。进一步对高延时部份进行剖析后发现,这些高延时音讯平均地散布于整个测试期间(如上图右所示)。依据咱们的教训,这通常是 Envoy 外部转发音讯的 worker 在周期性的执行一些耗费 CPU 的工作,导致有一部分音讯没方法及时转发而引起的。

深入研究 Envoy 在 istio 数据面的性能实现后,咱们发现 mixer 遥测可能是导致这个问题的根本原因。Mixer 是 istio 老版本 (1.4 及以前) 实现遥测和策略查看性能的一个组件。在数据面的 Envoy 中,Mixer 会提取所有音讯的属性,而后批量压缩上报到 mixer server,而属性的提取和压缩是一个高 CPU 的耗费的操作,这会引起延时数据分析中失去的后果:高延时音讯转发异样增多。

在确定了起因之后,咱们对 Envoy 的架构作了一些改良,给它减少了执行非关键工作的 AsyncWorker 线程,称为异步工作线程。通过把遥测的逻辑拆分进去放到了 AsyncWorker 线程中去执行,就解决了 worker 线程被阻塞的问题,进而能够升高 envoy 转发音讯的延时。

进行架构优化之后,咱们也做了比照测试,上图左测是延时与音讯数量图,能够看到它高延时局部失去显著的改善。上图右能够看出 Envoy 整体的延时升高了 40% 以上。

优化 Envoy 架构给咱们带来了第一手的教训,首先 CPU 是影响 Istio 数据面性能的要害资源,它的瓶颈次要呈现在 CPU 下面,而不是网络 IO 操作。第二,咱们对 Envoy 进行架构优化,能够升高延时,然而没有解决基本问题,因为 CPU 的应用没有升高,只是遥测逻辑转移到另外的线程中执行,升高 Envoy 转发音讯的延时。优化 CPU 使用率才是数据面优化的外围。第三点,Envoy 的不同组件当中,mixer 消化掉了 30% 左右的 CPU,而遥测是 mixer 的外围性能,因而后续遥测优化就变成了优化的重要方向。

怎么进行遥测优化呢?其实 mixer 实现遥测是非常复杂的一套架构,应用 Istio mixer 遥测的人都深有体会,幸好 istio 新版本中,不止对 istio 的管制面作了大的调整,在数据面 mixer 也同样被移除了,意味着 Envoy 中高耗费的遥测就不会存在了,咱们是基于 istio 在做外部的 service mesh,从社区失去这个音讯之后,咱们也疾速跟进,引入适配新的架构。

没有 Mixer 之后,遥测是如何实现的。Envoy 提供了应用 wasm 对其进行扩大的形式,以放弃架构的灵活性。而 istio 社区基于 Wasm 的扩大开发了一个 stats extension 扩大,实现了一个新的遥测计划。与 mixer 遥测相比,这个 stats extension 不再上报全量数据到 mixer server,只是在 Envoy 内的 stats 子系统中生成遥测指标。遥测零碎拉取 Envoy 的指标,就能够取得整个遥测数据,会大大降低遥测在数据面的性能耗费。

而后咱们对 istio 1.5 应用 Wasm 的遥测,做了一个性能的测试。发现整个 Envoy 代理在同样测试条件下,它的 CPU 升高 10%,而应用 mixer 的遥测其实占用了 30% 的 CPU,外面大部分逻辑是在执行遥测。按咱们的了解,Envoy 至多应该有 20% 的 CPU 降落,然而实际效果只有 10% 左右,这是为什么呢?

新架构下咱们遇到了新的问题。咱们对新架构进行了一些实现原理和技术细节上的剖析,发现 Envoy 应用 Wasm 的扩大形式,尽管带来了灵活性和可扩展性,然而对性能有肯定的影响。

首先,Wasm 扩大机制跟 Envoy host 环境是通过内存拷贝的形式进行通信,这是 Wasm 虚拟机的隔离性机制决定的。Envoy 为了放弃架构灵活性的同时保障性能,使设计了一个非 Wasm 虚拟机运行扩大(如 stats extension)的模式,即 NullVM 模式,它是一个假的 Wasm 虚拟机,实际上运行的扩大还是被编译在 Envoy 外部,但它也逃离不掉 Wasm 架构带来的内存拷贝影响。

其次,在实现 extension 与 Envoy 的通信时,一个属性的获取要通过屡次的内存拷贝,是一个非常复杂的过程。如上图所示,获取 request.url 这个属性须要在 Envoy 的内存和 Wasm 虚拟机内存之间进行一个简单的拷贝操作,这种形式的耗费远大于通过援用或指针提取属性。

第三,在实现遥测的时候,有大量的属性须要获取,通常有十几二十个属性,因而 Wasm 扩大带来的总体额定损耗十分可观。

另外,Wasm 实现的遥测性能还须要另外一个叫做 metadata_exchange 扩大的反对。metadata_exchange 用来取得调用对端的一些节点信息,而 metadata_exchange 扩大运行在另外一个虚拟机当中,通过 Envoy 的 Filter state 机制与 stats 扩大进行通信,进一步减少了遥测的额定耗费。

那么如何去优化呢?简略对 Wasm 插件优化是没有太大帮忙,因为它的底层 Wasm 机制曾经决定了它有不少的性能损耗,所以咱们就开发了一个新的遥测插件 tstats。
tstats 应用 Envoy 原生的扩大形式开发。在 tstats 扩大外部,实现了遥测和 metadata_exchange 的联合,打消了 Wasm 带来的性能弊病。Tstats 遥测与社区遥测兼容,生成雷同的指标,tstats 基于 istio 管制面的 EnvoyFilter CRD 进行部署,用户能够平滑降级,当用户发现 tstats 的性能没有满足需要或者呈现一些问题时,也能够切换应用到社区提供的遥测扩大。

在 tstats 扩大还优化了遥测指标的计算过程。在计算指标的时候有许多维度信息须要填充,(目前大指标有二十几个维度的填充),这其实是一个比较复杂的操作,其实,有很多指标的维度都是节点信息,就是发动服务调用的客户端和服务端的一些信息,如服务名、版本等等。其实咱们能够将它进行一些缓存,减速这些指标的计算。

通过优化之后,比照 tstats 遥测和官网的基于 Wasm 的遥测的性能,咱们发现 CPU 升高了 10 到 20%,绝对于老版本的 mixer 来说升高了 20% 以上,合乎了咱们对 envoy 性能调研的一个预期。上图右能够看到在延时上有一个显著的升高,即便在 P99 在不同的 QPS 下,也会有 20% 到 40% 的总体升高(这个延时是应用 echo service 做 End-to-End 压测失去的)。

应用火焰图从新察看一下 Envoy 外部的 CPU 应用散布,咱们发现 tstats 遥测插件占用 CPU 的比例显著更少,而应用 wasm 的遥测插件有一个显著的 CPU 占用来实现遥测,这也证实了 tstats 优化是有成果的。

总结

后面咱们分享了在优化 istio 数据面过程当中,在内核态和 Envoy 内摸索的一些教训。这是咱们优化的次要内容,当然还有一些其它的优化点,例如:

  • 应用 XDP 进行减速,因为因为 istio proxy 的引入,Pod 和 Pod 之间的拜访实际上是不须要通过主机上的 iptables 规定解决。基于这一点,咱们能够利用 XDP 的疾速转发能力间接将包发送到对应的网卡,实现疾速转发。
  • 链路跟踪在 Envoy 中耗费的 CPU 也比拟可观,即便在 1% 的采样率下也耗费了 8% 的 CPU,是能够进行优化的,所以咱们也在做这部分的工作。
  • Envoy 外部有十分多的内置统计,Istio 的一些指标与 Envoy 内置的指标有一部分反复,能够思考进行一些裁剪优化,或者减少一些个性开关,当不须要应用的时候对它进行敞开。

总体来说,Istio 数据面性能的损耗散布在各个环节,并不是独自的内核态音讯转发或者用户态 Envoy 就耗费特地多。在应用 Mixer 架构的 Istio 版本中,Envoy 内一个显著的性能热点,mixer 遥测,这也在版本迭代中逐渐解决了。

最初,在进行 Istio 数据面优化的时候须要综合思考各个环节,这也是咱们目前总体上对 Istio 数据面性能的一个意识,通过这次分享,心愿社区和大家都会在更重视 Istio 数据面的性能,帮忙 ServiceMesh 更好地落地。腾讯云基于 Istio 提供了云上 ServiceMesh 产品 TCM,大家有趣味能够来体验。

问题

  • 怎么判断我的项目须要应用服务网格?

    服务网格解决的最间接的场景就是你的服务须要进行微服务治理,然而你们之前可能有多个技术栈,没有一个对立的技术框架,比方没有应用 SpringCloud 等。短少微服务治理能力,然而又想最低老本取得链路跟踪、监控、流量治理、熔断等这样的能力,这个时候能够应用服务网格实现。

  • 这次优化有没有思考到回归到社区?

    其实咱们也思考过这个问题,咱们在进行 mixer 优化的时候,过后思考到须要对 Envoy 做比拟多的改变,并且理解到社区规划从架构中去掉 mixer,所以这个并没有回归到社区,异步工作线程架构的计划目前保留在外部。对于第二点开发的 tstats 扩大,它的性能和社区的遥测是一样的,如果提交到社区咱们感觉性能会有重叠,所以没有提交给社区。

  • 服务网格数据调优给当初腾讯的业务带来了哪些扭转?

    我想这里次要还是可观测性下面吧,之前很多的服务和开发,他们的监控和调用面的下面做得都是差强人意的,然而他们在业务的压力之下,其实是没有很欠缺的形式、没有很大的能源疾速实现这些服务治理的性能,应用 istio 之后,有不少团队都取得了这样的能力,他们给咱们的反馈都是比拟好的。

  • 在缩小提早方面,腾讯做了哪些调整,服务网格当初是否曾经成熟,对开发者是否敌对?

    在提早方面,咱们对性能的次要摸索就是明天分享的内容,咱们最开始就留神到延时比拟高,而后在内核做了相应的优化,并且钻研了在 Envoy 内为什么会有这些提早。所以咱们得出的论断,CPU 是外围的资源,须要尽量升高数据面 Proxy 代理对 CPU 的应用,这是咱们做所有优化最外围的出发点,当 CPU 降下来,延时就会升高。服务网格当初是否曾经成熟。我感觉不同的人有不同答案,因为对一些团队,目前他们应用服务网格应用得很好的,因为他们有多个技术栈,没有对立的框架。他们用了之后,取得这些流量的治理和监控等等能力,其实曾经满足了他们的需要。然而对一些成熟的比拟大的服务,数据面性能下面可能会有一些影响,这个须要相应的团队进行认真的评估能力决定,并没方法说它肯定就是能在任何场景下能够间接替换现有的各个团队的服务治理的形式。

  • 为什么不间接思考 1.6?

    因为咱们做产品化的时候,周期还是比拟长的。istio 社区发版本的速度还是比拟快的,咱们还在做 1.5 产品化的时候,可能做着做着,istio1.6 版本就收回来了,所以咱们也在不停更新跟迭代,始终在追随社区,目前次要还是在 1.5 版本上。其实咱们在 1.4 的时候就开始做当初的产品了。

  • 公司在引入多种云原生架构,包含 SpringCloud 和 Dubbo,作为运维,有必要用 Istio 做服务治理吗?另外 SpringCloud 和 Dubbo 这种架构迁徙到 Istio,如何调整?

    目前 SpringCloud 和 Dubbo 都有不错的服务治理性能,如果没有十分紧迫的需要,比方你们又须要引入新的服务并且用别的语言实现,我感觉持续应用这样的框架,可能引入 istio 没有太大的劣势。然而如果思考进行更大规模的服务治理,包含交融 SpringCloud 和 Dubbo, 则能够思考应用 istio 进行一个合并的,然而这个落地会比较复杂。那么 SpringCloud 和 Dubbo 迁徙到 Istio 如何调整?目前最简单的就是他们的服务注册机制不一样,服务注册模型不一样。咱们之前外部也有在预研如何提供一个对立的服务注册模型,以综合 Istio 和其它技术框架如 SpringCloud 的服务注册和服务发现,以及 SpringCloud 如何迁徙进来。这个比较复杂,须要对 SDK 做一些改变,我感觉能够下来再进行交换。

【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!

正文完
 0