性能提升40-腾讯-TKE-用-eBPF-绕过-conntrack-优化-K8s-Service

4次阅读

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

Kubernetes Service 用于实现集群中业务之间的互相调用和负载均衡,目前社区的实现主要有 userspace,iptables 和 IPVS 三种模式。IPVS 模式的性能最好,但依然有优化的空间。该模式利用 IPVS 内核模块实现 DNAT,利用 nf_conntrack/iptables 实现 SNAT。nf_conntrack 是为通用目的设计的,其内部的状态和流程都比较复杂,带来很大的性能损耗。

腾讯云 TKE 团队 开发了新的 IPVS-BPF 模式,完全绕过 nf_conntrack 的处理逻辑,使用 eBPF 完成 SNAT 功能。对最常用的 POD 访问 ClusterIP 场景,短连接性能提升 40%,p99 时延降低31%;NodePort 场景提升更多。详情见下表和 性能测量 章节。

一、容器网络现状

iptables 模式

存在的问题:

1.可扩展性差。随着 service 数据达到数千个,其控制面和数据面的性能都会急剧下降。原因在于 iptables 控制面的接口设计中,每添加一条规则,需要遍历和修改所有的规则,使得其控制面性能是O(n²)。在数据面,规则是用链表组织的,使得其数据面的性能是O(n)

2.LB 调度算法仅支持随机转发。

IPVS 模式

IPVS 是专门为 LB 设计的。它用 hash table 管理 service,对 service 的增删查找都是 O(1) 的时间复杂度。不过 IPVS 内核模块没有 SNAT 功能,因此借用了 iptables 的 SNAT 功能。IPVS 针对报文做 DNAT 后,将连接信息保存在 nf_conntrack 中,iptables 据此接力做 SNAT。该模式是目前 Kubernetes 网络性能最好的选择。但是由于 nf_conntrack 的复杂性,带来了很大的性能损耗。

二、IPVS-BPF 方案介绍

eBPF 介绍

eBPF 是 Linux 内核中软件实现的虚拟机。用户把 eBPF 程序编译为 eBPF 指令,然后通过 bpf()系统调用将 eBPF 指令加载到内核的特定挂载点,由特定的事件来触发 eBPF 指令的执行。在挂载 eBPF 指令时内核会进行充分验证,避免 eBPF 代码影响内核的安全和稳定性。另外内核也会进行 JIT 编译,把 eBPF 指令翻译为本地指令,减少性能开销。

内核在网络处理路径上中预置了很多 eBPF 的挂载点,例如 xdp, qdisc, tcp-bpf, socket 等。eBPF 程序可以加载到这些挂载点,并调用内核提供的特定 API 来修改和控制网络报文。eBPF 程序可以通过 map 数据结构来保存和交换数据。

基于 eBPF 的 IPVS-BPF 优化方案

针对 nf_conntrack 带来的性能问题,腾讯 TKE 团队设计实现了 IPVS-BPF。核心思想是绕过 nf_conntrack,减少处理每个报文的指令数目,从而节约 CPU,提高性能。其主要逻辑如下:

  1. 在 IPVS 内核模块中引入开关,支持原生 IPVS 逻辑和 IPVS-BPF 逻辑的切换
  2. 在 IPVS-BPF 模式下,将 IPVS hook 点从 LOCALIN 前移到 PREROUTING,使访问 service 的请求绕过 nf_conntrack
  3. 在 IPVS 新建连接和删除连接的代码中,相应的增删 eBPF map 中的 session 信息
  4. 在 qdisc 挂载 eBPF 的 SNAT 代码,根据 eBPF map 中的 session 信息执行 SNAT

此外,针对 icmp, fragmentation 均有专门处理,详细背景和细节,会在后续的 QCon 在线会议上介绍,欢迎一起探讨。

优化前后报文处理流程的对比

可以看到,报文处理流程得到了极大简化。

为什么不直接采用全 eBPF 方式

很多读者会问,为什么还要用 IPVS 模块跟 eBPF 相结合,而不是直接使用 eBPF 把 Service 功能都实现了呢?

我们在设计之初也仔细研究了这个问题, 主要有以下几点考虑:

  • nf_conntrack 对 CPU 指令和时延的消耗,大于 IPVS 模块,是转发路径的头号性能杀手。而 IPVS 本身是为高性能而设计的,不是性能瓶颈所在
  • IPVS 有接近 20 年的历史,广泛应用于生产环境,性能和成熟度都有保障
  • IPVS 内部通过 timer 来维护 session 表的老化,而 eBPF 不支持 timer, 只能通过用户空间代码来协同维护 session 表
  • IPVS 支持丰富的调度策略,用 eBPF 来重写这些调度策略,代码量大不说,很多调度策略需要的循环语句,eBPF 也不支持

我们的目标是实现代码量可控,能落地的优化方案。基于以上考虑,我们选择了复用 IPVS 模块,绕过 nf_conntrack,用 eBPF 完成 SNAT 的方案。最终数据面代码量为:500+ 行 BPF 代码,1000+ 行 IPVS 模块改动(大部分为辅助 SNAT map 管理的新增代码)。

三、性能测量

本章节通过量化分析的方法,用 perf 工具读取 CPU 性能计数器,从微观的角度解释宏观的性能数据。本文采用的压测程序是 wrk 和 iperf。

测试环境

复现该测试需要注意两点:

  1. 不同的集群和机器,即使机型都一样,也可能因为各自母机和机架的拓扑不同,造成性能数据有背景差异。为了减少这类差异带来的误差,我们对比 IPVS 模式和 IPVS-BPF 模式时,是使用同一个集群,同样一组后端 Pod, 并且使用同一个 LB 节点。先在 IPVS 模式下测出 IPVS 性能数据,然后把 LB 节点切换到 IPVS-BPF 模式, 再测出 IPVS-BPF 模式的性能数据。(注:切换模式是通过后台把控制面从 kube-proxy 切换为 kube-proxy-bpf 来实现的,产品功能上并不支持这样在线切换)
  2. 本测试的目标是测量 LB 上软件模块优化对于访问 service 性能的影响,不能让客户端和 RS 目标服务器的带宽与 CPU 成为瓶颈。所以被压测的 LB 节点采用 1 核机型,不运行后端 Pod 实例;而运行后端服务的节点采用 8 核机型

NodePort

为了采集 CPI 等指标,这里 LB 节点 (红色部分) 采用黑石裸金属机器,但通过 hotplug 只打开一个核,关闭其余核。

ClusterIP

这里 LB 节点 (左边的 Node) 采用 SA2 1 核 1G 机型。

测量结果

IPVS-BPF 模式相对 IPVS 模式,Nodeport 短连接性能提高了 64%,clusterIP 短连接性能提高了 40%。

NodePort 优化效果更明显,是因为 NodePort 需要 SNAT,而我们的 eBPF SNAT 比 iptables SNAT 更高效,所以性能提升更多。

如上图所示,iperf 带宽测试中 IPVS-BPF 模式相对 IPVS mode 性能提升了 22%。

上图中,wrk 测试表明 nodePort service 短连接 p99 延迟降低了 47%.

上图中,wrl 测试表明 clusterIP service 短连接的 p99 延迟降低了 31%。

指令数和 CPI

上图中从 Perf 工具看,平均每个请求耗费的 CPU 指令数, IPVS-BPF 模式下降了 38%。这也是性能提升的最主要原因。

IPVS-BPF 模式下 CPI 略有增加,大概 16%。

测试总结

Service 类型 短连接 cps 短连接 p99 延迟 长连接吞吐
clusterIP +40% -31% 无,见下文
nodePort +64% -47% +22%

如上表,IPVS-BPF 模式相对原生 IPVS 模式,Nodeport 处理短连接性能提升了 64%,p99 延迟降低了 47%,处理长连接带宽提升了 22%;ClusterIP 处理短连接吞吐量提升了 40%, p99 延迟降低了 31%。

测试 ClusterIP 长连接吞吐时,iperf 本身消耗了 99% 的 CPU,使得优化效果不容易直接测量。另外我们还发现 IPVS-BPF 模式下 CPI 有增加,值得进一步研究。

四、其他优化,特性限制和后续工作

在开发 IPVS-BPF 方案过程中,顺便解决或优化了一些其他问题

  • conn_reuse_mode = 1 时新建性能低以及 no route to host 问题

    这个问题是当 client 发起大量新建 TCP 连接时,新的连接被转发到 terminating 的 pod 上,导致持续丢包。此问题在 IPVS conn_reuse_mode= 1 的情况下不会有。但是 conn_reuse_mode= 1 时,有另外的新建连接性能急剧下降的 bug, 故一般都设置成了 conn_reuse_mode=0。我们在 TencentOS 内核中彻底修复了该问题,代码在 ef8004f8, 8ec35911, 07a6e5ff63 同时也正在向内核社区提交修复。

  • DNS 解析偶尔 5s 延时

    iptables SNAT 分配 lport 到调用插入 nf_conntrack,这中间是采用乐观锁机制。这中间如果发生竞争,相同的 lport 和五元组同时插入 nf_conntrack 会导致丢包。在 IPVS-BPF 模式下,SNAT 选择 lport 的过程和插入 hash table 的过程在同一个循环中,循环次数最大为 5 次,从而减少了该问题的概率。

  • externalIp 优化造成 clb 健康检查失败问题

    详情见:https://github.com/kubernetes…

特性限制

  • Pod 访问自身所在的 service,IPVS-BPF 模式会把请求转发给其他 Pod,不会把请求转发给 Pod 自己

后续工作

  • 借鉴 Cilium 提出的方法,利用 eBPF 进一步优化 clusterIP 性能
  • 研究 IPVS-BPF 模式下 CPI 上升的原因,探索进一步提升性能的可能性

五、如何在 TKE 启用 IPVS-BPF 模式

如下图,在腾讯云 TKE 控制台创建集群时,高级设置 下的 Kube-proxy 代理模式 选项,选择 ipvs-bpf即可。

目前该特性需要申请白名单。请通过申请页提交申请。

六、相关专利

本产品产生的相关专利申请如下:

2019050831CN 一种报文传输的方法及相关装置

2019070906CN 负载均衡方法、装置、设备及存储介质

2020030535CN 一种利用 eBPF 技术探测网络服务应用闲置的方法

2020040017CN 宿主机实时负载感知的自适应的负载均衡调度算法

正文完
 0