KubeCon 2021|使用 eBPF 代替 iptables 优化服务网格数据面性能
作者
刘旭,腾讯云高级工程师,专注容器云原生领域,有多年大规模 Kubernetes 集群管理及微服务治理经验,现负责腾讯云服务网格 TCM 数据面产品架构设计和研发工作。
引言
目前以 Istio[1] 为代表的服务网格普遍使用 Sidecar 架构,并使用 iptables 将流量劫持到 Sidecar 代理,优点是对应用程序无侵入,但是 Sidecar 代理会增加请求时延和资源占用。
性能一直是用户十分关心的一个点,也是用户评估是否使用服务网格产品的关键因素,腾讯云 TCM 团队一直致力于优化服务网格性能,上周我们在 KubeCon 分享了使用 eBPF 代替 iptables 优化服务网格数据面性能的方案。

iptables 实现流量劫持
首先看一下当前社区使用的基于 iptables 的流量劫持方案,下图是一个 Pod 的创建过程,sidecar injector 会向 Pod 中注入两个容器,istio-init 和 istio-proxy
istio-init 是一个 init container,负责创建流量劫持相关的 iptables 规则,在创建完成后会退出
istio-proxy 中运行着 envoy,负责代理 Pod 的网络流量,iptables 会将请求劫持到 istio-proxy 处理

下图展示了 iptables 完成流量劫持的整个过程,这里简单说明下,感兴趣的同学可以查看[2]
Inbound iptables 将入流量重定向到 15006 端口,也就是 envoy 的 VirtualInboundListener,envoy 会根据请求的原始目的地址转发到应用程序的指定端口
Outbound iptables 将出流量重定向到 15001 端口,也就是 envoy 的 VirtualOutboundListener,envoy 会根据请求的原始目的地址以及 Host URL 等信息路由到指定后端

eBPF 实现流量劫持

eBPF(extended Berkeley Packet Filter) 是一种可以在 Linux 内核中运行用户编写的程序,而不需要修改内核代码或加载内核模块的技术,目前被广泛用于网络、安全、监控等领域。在 Kubernetes 社区最早也是最有影响的基于 eBPF 项目是 Cilium[4],Cilium 使用 eBPF 代替 iptables 优化 Service 性能。
Inbound
首先来看一下对入流量的劫持,对入流量的劫持主要使用 eBPF 程序 hook bind 系统调用完成。

eBPF 程序会劫持 bind 系统调用并修改地址,例如应用程序 bind 0.0.0.0:80 会被修改为 127.0.0.1:80,应用程序还有可能 bind ipv6 的地址,所以这里有两个 eBPF 程序分别处理 ipv4 和 ipv6 的 bind。
和 iptables 不同,iptables 可以针对每个 netns 单独设置规则,eBPF 程序 attach 到指定 hook 点后,会对整个系统都生效,例如 attach 到 bind 系统调用后,所有 Pod 内以及节点上进程调用 bind 都会触发 eBPF 程序,我们需要区分哪些调用是来自需要由 eBPF 完成流量劫持的 Pod。
在 K8s 中,除了 hostnetwork 的情况,每个 Pod 都有独立的 netns,而每个 netns 都有唯一的 cookie,因此我们将需要使用 eBPF 完成流量劫持的 Pod 对应的 netns cookie 保存在 cookie_map 中,eBPF 程序通过判断当前 socket 的 netns cookie 是否在 cookie_map 中来决定是否修改 bind 地址。
修改应用程序的 bind 地址后,还需要下发 pod_ip:80 listener 配置到 envoy,pod_ip:80 listener 会将请求转发到 127.0.0.1:80 也就是应用程序监听的地址,这样就实现了对入流量的劫持。但是这里有一个问题,由于 istio 使用 istio-proxy 用户启动 envoy,默认情况下非 root 用户不能 bind 1024 以下的特权端口,我们通过 istio-init 修改内核参数 sysctl net.ipv4.ip_unprivileged_port_start=0 解决了这个问题。

对比 iptables 和 eBPF 对入流量的劫持,iptables 方案每个包都需要 conntrack 处理,而 eBPF 方案只有在应用程序调用 bind 时执行一次,之后不会再执行,减少了性能开销。
Outbound
再来看一下对出流量的劫持,对出流量的劫持比较复杂,根据协议分为 TCP 和 UDP 两种情况。
TCP 流量劫持

对 TCP 的出流量劫持过程:
_coonect4通过劫持 connect 系统调用将目的地址修改为127.0.0.1:15001,也就是 envoy 的 VirtualOutboundListerer,同时将连接的原始目的地址保存在sk_storage_map在 TCP 连接建立完成后,
sockops会读取sk_storage_map中的数据,并以四元组(源IP、目的IP、源端口、目的端口)为 key 将原始目的地址保存在origin_dst_map_getsockopt通过劫持 getsockopt 系统调用,读取origin_dst_map中的数据将原始目的地址返回给 envoy
UDP 流量劫持

istio 在 1.8 版本支持了智能 DNS 代理[5],开启后 iptables 会将 DNS 请求劫持到 Sidecar 处理,我们也需要用 eBPF 实现相同逻辑,对于 TCP DNS 的劫持和上面类似,对 UDP DNS 的劫持见下图

对 UDP 的出流量劫持过程:
_connect4和_sendmsg4都是负责修改 UDP 的目的地址为 127.0.0.1:15053 并保存原始的目的地址到sk_storage_map,因为 Linux 提供两种发送 UDP 数据的方式- 先调用 connect 再调用 send,这种情况由
_connect4处理 - 直接调用 sendto,这种情况由
_sendmsg4处理
- 先调用 connect 再调用 send,这种情况由
recvmsg4通过读取sk_storage_map将回包的源地址改为原始的目的地址,这是因为有些应用程序,例如 nslookup 会校验回包的源地址。
对于 TCP 和 connected UDP,iptables 方案每个包都需要 conntrack 处理,而eBPF 方案的开销是一次性的,只需要在 socket 建立时执行一次,降低了性能开销。
Sockmap
使用 sockmap 优化服务网格性能的方案最早由 cilium 提出,我们的方案也参考了 cilium,这里借用 cilium 的两张图来说明下优化效果

优化前 Sidecar 代理与应用程序间的网络通信都需要经过 TCP/IP 协议栈处理

优化后 Sidecar 代理与应用程序间的网络通信绕过了 TCP/IP 协议栈,如果两个 Pod 在同一节点上,两个 Pod 间的网络通信也可以被优化。这里简单说明下 sockmap 的优化原理,感兴趣的同学可以查看[6][7]。

sock_hash是一个存储 socket 信息的 eBPF map,key 是四元组(源IP、目的IP、源端口、目的端口)_sockops负责监听 socket 事件,并将 socket 信息保存在sock_hash_sk_msg会拦截 sendmsg 系统调用,然后到sock_hash中查找对端 socket,如果找到会调用bpf_msg_redirect_hash直接将数据发送给对端 socket
问题
但是用四元组做为 key 可能会存在冲突的问题,例如在同一节点上的两个 Pod 中,envoy 使用同一源端口 50000 请求应用程序的 80 端口。

为了解决这个问题,我们在 key 中添加了 netns cookie,同时对于非 localhost 的请求将 cookie 设置为 0,这样既保证了 key 不会冲突,又可以加速同一节点上两个 Pod 间的网络通信。

但是之前版本的内核不支持在 sockops 和 sk_msg 这两种 eBPF 程序中获取 netns cookie 信息,因此我们提交了两个 patch [8 ][9]到内核社区,目前已合入 5.15 版本。
架构

整个方案的架构如图所示,istio-ebpf 以 DaemonSet 的形式运行在节点上,负责 load/attach eBPF 程序和创建 eBPF map。istio-init 容器仍然保留,但是不再创建 iptables 规则,而是更新 eBPF map,istio-init 会将 Pod 的 netns cookie 保存在 cookie_map 中。同时我们也修改了 istiod,istiod 会根据 Pod 的流量劫持模式(iptables/eBPF)下发不同的 xDS 配置。
性能对比
测试环境:Ubuntu 21.04 5.15.7



- 同等条件下,使用 eBPF 可减少 20% 的 System CPU 占用
- 同等条件下,使用 eBPF 可提高 20% QPS
- 同等条件下,使用 eBPF 可降低请求时延
总结
服务网格的 Sidecar 架构不可避免的会增加请求时延和资源占用,我们通过使用 eBPF 代替 iptables 实现流量劫持,同时使用 sockmap 加速 Sidecar 代理和应用程序间的网络通信,在一定程度上降低了请求时延和资源开销,由于内核版本等限制这一方案预计会在明年初上线,TCM 团队将持续探索新的性能优化方向。
Reference
[1] https://istio.io
[2] https://jimmysong.io/blog/sidecar-injection-iptables-and-traffic-routing
[3] https://ebpf.io
[5] https://istio.io/latest/blog/2020/dns-proxy
[6] https://arthurchiao.art/blog/socket-acceleration-with-ebpf-zh
[7] https://github.com/cilium/cilium/tree/v1.11.0/bpf/sockops
[8] https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=6cf1770d
[9] https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=fab60e29f
关于我们
更多关于云原生的案例和知识,可关注同名【腾讯云原生】公众号~
福利:
①公众号后台回复【手册】,可获得《腾讯云原生路线图手册》&《腾讯云原生最佳实践》~
②公众号后台回复【系列】,可获得《15个系列100+篇超实用云原生原创干货合集》,包含Kubernetes 降本增效、K8s 性能优化实践、最佳实践等系列。
③公众号后台回复【白皮书】,可获得《腾讯云容器安全白皮书》&《降本之源-云原生成本管理白皮书v1.0》
【腾讯云原生】云说新品、云研新术、云游新活、云赏资讯,扫码关注同名公众号,及时获取更多干货!!
KubeCon 2021|使用 eBPF 代替 iptables 优化服务网格数据面性能的更多相关文章
- 服务网格数据平面的关键:层层剖析Envoy配置
Envoy是一种高性能C++分布式代理,专为单个服务和应用程序设计.作为Service Mesh中的重要组件,充分理解其配置就显得尤为重要.本文列出了使用Envoy而不用其他代理的原因.并给出了Env ...
- eBPF会成为服务网格的未来吗?
服务网格现状 服务网格为服务提供了复杂的应用层网络管理,如服务发现.流量路由.弹性(超时/重试/断路).认证/授权.可观察性(日志/度量/追踪)等. 在分布式应用的早期,这些要求是通过直接将所需的逻辑 ...
- 性能提升40%: 腾讯 TKE 用 eBPF 绕过 conntrack 优化 K8s Service
Kubernetes Service 用于实现集群中业务之间的互相调用和负载均衡,目前社区的实现主要有userspace,iptables和IPVS三种模式.IPVS模式的性能最好,但依然有优化的空间 ...
- 腾讯 TKE 厉害了!用 eBPF绕过 conntrack 优化K8s Service,性能提升40%
Kubernetes Service[1] 用于实现集群中业务之间的互相调用和负载均衡,目前社区的实现主要有userspace,iptables和IPVS三种模式.IPVS模式的性能最好,但依然有优化 ...
- [转] 携程App网络服务通道治理和性能优化@2016
App网络服务的高可靠和低延迟对于无线业务稳定发展至关重要,过去两年来我们一直在持续优化App网络服务的性能,到今年Q2结束时基本完成了App网络服务通道治理和性能优化的阶段性目标,特此撰文总结其中的 ...
- 大规模服务网格性能优化 | Aeraki xDS 按需加载
作者 钟华,腾讯云专家工程师,Istio project member.contributor,专注于容器和服务网格,在容器化和服务网格生产落地方面具有丰富经验,目前负责 Tencent Cloud ...
- 网站的优化----首页优化---app调取服务端数据
高并发经常会发生在有大活跃用户量来访问网站的某个点,例如用户高聚集的业务场景中,如:抢购,促销等.为了让用户流畅的访问网站,来根据自己的业务设计适合系统的处理方案. //对于APP网站首页数据,通常是 ...
- Cilium 1.11 发布,带来内核级服务网格、拓扑感知路由....
原文链接:https://isovalent.com/blog/post/2021-12-release-111 作者:Cilium 母公司 Isovalent 团队 译者:范彬,狄卫华,米开朗基杨 ...
- 使用 Istio CNI 支持强安全 TKE Stack 集群的服务网格流量捕获
作者 陈计节,企业应用云原生架构师,在腾讯企业 IT 负责云原生应用治理产品的设计与研发工作,主要研究利用容器集群和服务网格等云原生实践模式降低微服务开发与治理门槛并提升运营效率. 摘要 给需要快速解 ...
随机推荐
- OpenCV常用操作函数大全
https://blog.csdn.net/Vici__/article/details/100714822 目录 cv2常用类: 1.图片加载.显示和保存 2.图像显示窗口创建与销毁 3.图片的常用 ...
- SQL Server学习之路:建立数据库、建立表
1.前言 配置是win10+SQL Server 2012,使用的GUI管理工具是SQL Server 2012自带的SQL Server Management Studio(以下简称SSMS).本系 ...
- Arduino uno r3 使用 ESP8266 UART-WiFi 透传模块
一.所需硬件材料 1.ESP8266:01s某宝上3.5块钱 2.杜邦线:某宝几块钱一组40P,这里只需要三根,用于连接 树莓派与继电器 3.烧录器 二.ESP8266 AT固件烧录 ESP8266主 ...
- HelloWorld与java运行机制
HelloWorld 新建文件夹存放代码 新建一个java文件 文件后缀为.java Hello.java 注意文件拓展名改为java文件 编写代码 public class Hello{ #类名 p ...
- SpringCloud微服务实战——搭建企业级开发框架(二十五):实现多租户多平台短信通知服务
目前系统集成短信似乎是必不可少的部分,由于各种云平台都提供了不同的短信通道,这里我们增加多租户多通道的短信验证码,并增加配置项,使系统可以支持多家云平台提供的短信服务.这里以阿里云和腾讯云为例,集成短 ...
- IT公司都不喜欢招培训班出来的学生,那培训班的意义何在呢?
我一方面做过培训学校的老师,现在上班之余,还在培训学校做兼职老师,另一方面做过大厂和外求的技术面试官,主要是java方向的,应该对这个话题有充分的话语权. 在本文里,就从培训班的作用. ...
- 【Meta】16s rRNA和16s rDNA的区别
在文章或宣传稿中经常看到两者滥用,实际上是不同的. 首先是各个字母的含义: 16S中的"S"是一个沉降系数,亦即反映生物大分子在离心场中向下沉降速度的一个指标,值越高,说明分子越大 ...
- C语言中内存对齐与结构体
结构体 结构体是一种新的数据类型,对C语言的数据类型进行了极大的扩充. struct STU{ int age; char name[15]; }; struct STU a; //结构体实例 str ...
- 听老外吐槽框架设计,Why I Hate Frameworks?
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. Hello,小伙伴们,今天不聊技术,分享点有意思的东西.前段时间,表弟给我发过来一篇老外写的文章,以略带讽刺的对话方式调侃了自己对框架的看法,我 ...
- (亿级流量)分布式防重复提交token设计
大型互联网项目中,很多流量都达到亿级.同一时间很多的人在使用,而每个用户提交表单的时候都可能会出现重复点击的情况,此时如果不做好控制,那么系统将会产生很多的数据重复的问题.怎样去设计一个高可用的防重复 ...
