目前以 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 处理

  • 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 间的网络通信。

但是之前版本的内核不支持在 sockopssk_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

[4] https://cilium.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

- END -


看完一键三连在看转发点赞

是对文章最大的赞赏,极客重生感谢你

推荐阅读

定个目标|建立自己的技术知识体系

从C10K到C10M高性能网络的探索与实践

万字长文|深入理解XDP全景指南

你好,这里是极客重生,我是阿荣,大家都叫我荣哥,从华为->外企->到互联网大厂,目前是大厂资深工程师,多次获得五星员工,多年职场经验,技术扎实,专业后端开发和后台架构设计,热爱底层技术,丰富的实战经验,分享技术的本质原理,希望帮助更多人蜕变重生,拿BAT大厂offer,培养高级工程师能力,成为技术专家,实现高薪梦想,期待你的关注!点击蓝字查看我的成长之路

校招/社招/简历/面试技巧/大厂技术栈分析/后端开发进阶/优秀开源项目/直播分享/技术视野/实战高手等, 极客星球希望成为最有技术价值星球,尽最大努力为星球的同学提供技术和成长帮助!详情查看->极客星球

求点赞,在看,分享三连

性能优化实战|使用eBPF代替iptables优化服务网格数据面性能相关推荐

  1. mysql参数优化步骤_MySQL架构优化实战系列4:SQL优化步骤与常用管理命令2(转)

    MySQL架构优化实战系列4:SQL优化步骤与常用管理命令 原文:http://dbaplus.cn/news-11-649-1.html 一.SQL语句优化步骤 1.查看MySQL状态及配置 sho ...

  2. 基于linux的千兆网卡驱动程序实现及数据传输效率优化,嵌入式Linux下网卡驱动的实现与数据转发性能优化分析...

    摘要: 伴随着互联网的快速发展和后PC时代的到来,嵌入式系统已逐步成为当今IT产业的焦点之一,广阔的市场前景使嵌入式系统获得了空前的发展机遇.由于Linux操作系统具有代码开放.内核可裁减.网络功能强 ...

  3. 【在线网课】Java高性能高并发秒杀系统方案优化实战

    java教程视频讲座简介: Java高性能高并发秒杀系统方案优化实战 Java秒杀系统方案优化 高性能高并发实战 以"秒杀"这一Java高性能高并发的试金石场景为例,带你通过一系列 ...

  4. 大数据之数据库mysql优化实战(一)

    2019独角兽企业重金招聘Python工程师标准>>> :facepunch: 大数据之数据库mysql优化实战(一) 首先你要有数据,不然怎么测试,几百条就算了,还没跑就完了. 本 ...

  5. 和Sidecars说再见,看eBPF如何解决服务网格

    和Sidecars说再见,看eBPF如何解决服务网格 How eBPF will solve Service Mesh - Goodbye Sidecars https://isovalent.com ...

  6. eBPF 如何简化服务网格

    今天有几个服务网格的产品和项目,承诺简化应用微服务之间的连接,同时提供额外的功能,如安全连接.可观察性和流量管理.但正如我们在过去几年中反复看到的那样,对服务网格的兴奋已经被对额外的复杂性和开销的实际 ...

  7. Istio、eBPF 和 RSocket Broker:深入研究服务网格

    文章目录 介绍 1.服务治理 服务注册和发现 负载均衡 2. 边车模式 3\. Service Mesh 之旅 **服务网格** 4\. Istio 快速浏览 Istio 架构 核心组件 Envoy ...

  8. 性能提升40%:腾讯TKE用eBPF绕过conntrack优化Kubernetes Service

    Kubernetes Service[1] 用于实现集群中业务之间的互相调用和负载均衡,目前社区的实现主要有userspace,iptables和IPVS三种模式.IPVS模式的性能最好,但依然有优化 ...

  9. 腾讯 TKE 厉害了!用 eBPF绕过 conntrack 优化K8s Service,性能提升40%

    Kubernetes Service[1] 用于实现集群中业务之间的互相调用和负载均衡,目前社区的实现主要有userspace,iptables和IPVS三种模式.IPVS模式的性能最好,但依然有优化 ...

最新文章

  1. python 数据类笔试题_一道 Python 类的笔试题详解
  2. Exchenge2007用户设置邮件转发到外网地址
  3. 列联表分析程序,以卢淑华书上的例子为例
  4. (Hook)SetWindowsHookEx和UnhookWindowsHookEx
  5. aix oracle 内存限制,请教 AIX 与 Linux 中,怎样分析Oracle的内存占用?
  6. 系统盘点Android开发者必须掌握的知识点,全网疯传
  7. 360数科张家兴:金融科技的本质是线上化和自动化
  8. Spring+SpringMVC+MyBatis+easyUI整合优化篇(十三)数据层优化-表规范、索引优化
  9. Qt之QtCreator Qt5示例丢失解决方案
  10. vscode之调试es6代码
  11. 系统学习机器学习之距离的度量(二)--DTW
  12. 量子链创始人:监管者应看到区块链科技的大局
  13. 泛微协同办公系统移动服务器,泛微协同办公平台Ecology系统重装迁移指导手册.pdf...
  14. android tabhost的使用方法,Android TabHost组件使用方法详解
  15. 我在富士康挨踢了七年(十三.悉尼工作篇 )
  16. Android系统预装Chrome并自定义主页
  17. 4.微信支付之刷卡支付
  18. lamp技术_LAMP技术简介:
  19. 上传图片为线上图片,可以在线访问
  20. 股票、期货、期权的差异

热门文章

  1. 图的定义存储和遍历(一级)
  2. web.xml文件中可以配置哪些内容?
  3. FastDFS简介和安装
  4. flyme禁止系统更新_魅族Flyme更新8.1.2.3A:重要系统更新!
  5. ‘复杂变简单‘的代码例子
  6. JAVA流程控制详解
  7. C# textBox1.Append/Text实现换行
  8. liunxC下零碎知识点的总结
  9. activiti 工作流 动态 设置 指定 节点任务人、责任人、组 的实现方式
  10. 0619-dedeCMS的安装、重装、目录说明、基本操作及注意事项