背景介绍
kubernetes 中的网络功能,主要包括 pod 网络,service 网络和网络策略组成。其中 pod 网络和网络策略,都是规定了模型,没有提供默认实现。而 service 网络作为 kubernetes 的特色部分,官方版本持续演进了多种实现:
service 实现说明
userspace 代理模式kube-proxy 负责 list/watch,规则设置,用户态转发。
iptables 代理模式kube-proxy 负责 list/watch,规则设置。iptables 相关内核模块负责转发。
ipvs 代理模式kube-proxy 负责 list/watch,规则设置。ipvs 相关内核模块负责转发。
在 kubernetes 中先后出现的几种 service 实现中,整体都是为了提供更高的性能和扩展性。
service 网络,本质上是一个分布式的服务器负载均衡,通过 daemonset 方式部署的 kube-proxy,监听 endpoint 和 service 资源,并在 node 本地生成转发表项。目前在生产环境中主要是 iptables 和 ipvs 方式,原理如下:
在本文中,介绍使用 socket ebpf 在 socket 层面完成负载均衡的逻辑,消除了逐报文 nat 转换处理,进一步提升 service 网络的转发性能。
基于 socket ebpf 的数据面实现
socket ebpf 数据面简介
无论 kube-proxy 采用 ipvs 还是 tc ebpf 服务网络加速模式,每个从 pod 发出网络请求都必然经过 ipvs 或者 tc ebpf,即 pod 《--》 service 《--》 pod,随着流量的增加必然会有性能开销, 那么是否可以直接在连接中将 service的clusterip 的地址直接换成对应的 pod ip。基于 kube-proxy+ipvs 实现的 service 网络服务,是基于逐报处理 +session 的方式来实现。
利用 socket ebpf,可以在不用直接处理报文和 nat 转换的前提下,实现了负载均衡逻辑。service 网络在同步上优化成 pod 《--》 pod,从而使service 网络性能基本等同于 pod 网络。软件结构如下:
在 linux 内核中,利用 bpf_prog_type_cgroup_sock 类型的 ebpf hook 可以针对 socket 系统调用挂接 hook,插入必要的 ebpf 程序。
通过 attach 到特定的 cgroup 的文件描述符,可以控制 hook 接口的作用范围。
利用 sock ebpf hook,我们可以在 socket 层面劫持特定的 socket 接口,来完成完成负载均衡逻辑。
pod-svc-pod 的转发行为转换成 pod-pod 的转发行为。
当前 linux 内核中不断完善相关的 hook,支持更多的 bpf_attach_type,部分距离如下:bpf_cgroup_inet_sock_createbpf_cgroup_inet4_bindbpf_cgroup_inet4_connectbpf_cgroup_udp4_sendmsgbpf_cgroup_udp4_recvmsgbpf_cgroup_getsockoptbpf_cgroup_inet4_getpeernamebpf_cgroup_inet_sock_release
tcp 工作流程
tcp 由于是有基于连接的,所以实现非常简明,只需要 hook connect 系统调用即可,如下所示:
connect 系统调用劫持逻辑:
1. 从 connect 调用上下文中取 dip+dport,查找 svc 表。找不到则不处理返回。
2. 查找亲和性会话,如果找到,得到 backend_id,转 4。否则转 3。
3. 随机调度,分配一个 backend。
4. 根据 backend_id,查 be 表,得到 be 的 ip+ 端口。
5. 更新亲和性信息。
6. 修改 connect 调用上下文中的 dip+dport 为 be 的 ip+port。
7. 完成。
在 socket 层面就完成了端口转换,对于 tcp 的 clusterip 访问,基本上可以等同于 pod 之间东西向的通信,将 clusterip 的开销降到最低。
不需要逐包的 dnat 行为。
不需要逐包的查找 svc 的行为。
udp 工作流程
udp 由于是无连接的,实现要复杂一些,如下图所示:
nat_sk 表的定义参见:lb4_reverse_nat_sk_map
劫持 connect 和 sendmsg 系统调用:
1. 从系统调用调用上下文中取 dip+dport,查找 svc 表。找不到则不处理返回。
2. 查找亲和性会话,如果找到,得到 backend_id,转 4,否则转 3。
3. 随机调度,分配一个 backend。
4. 根据 backend_id,查 be 表,得到 be 的 ip+端口。
5. 更新亲和性的相关表。
6. 更新 nat_sk 表,key 为 be 的 ip+port,value 为 svc的vip+vport。
7. 修改系统调用上下文中的 dip+dport 为 be 的 ip + port。
8. 完成。劫持 recvmsg 系统调用
1. 从系统调用上下文中远端 ip+port,查找 nat_sk 表,找不到则不处理返回。
2. 找到,取出其中的 ip+port,用来查找 svc 表,找不到,则删除 nat_sk 对应表项,返回。
3. 使用 nat_sk 中找到的 ip+port,设置系统调用上下文中远端的 ip+port。
4. 完成。关于地址修正问题
基于 socket ebpf 实现的 clusterip,在上述基本转发原理之外,还有一些特殊的细节需要考虑,其中一个需要特殊考虑就是 peer address 的问题。和 ipvs之类的实现不同,在 socket ebpf 的 clusterip 上,client 是和直接和 backend 通信的,中间的 service 被旁路了。
此时,如果 client 上的 app 调用 getpeername 之类的接口查询 peer address,这个时候获取到的地址和 connect 发起的地址是不一致的,如果 app对于 peeraddr 有判断或者特殊用途,可能会有意外情况。
针对这种情况,我们同样可以通过 ebpf 在 socket 层面来修正:
1、在guest kernel 上新增 bpf_attach_type,可以对 getpeername 和 getsockname 增加 hook 处理。
2、发起连接的时候,在相应的 socket hook 处理中,定义 map 记录响应的vip:vport 和 rsip:rsport 的对用关系。
3、当 app 要调用 getpeername/getsockname 接口的时候,利用 ebpf 程序修正返回的数据:修改上下文中的远端的 ip+port为vip+vport。
总结
和tc-ebpf/ipvs性能对比
测试环境:4vcpu + 8g mem 的安全容器实例,单 client + 单 clusterip + 12 backend。socket bpf:基于 socket ebpf 的 service 实现。tc ebpf:基于 cls-bpf 的 service 实现,目前已经在 ack 服务中应用。ipvs-raw:去掉所有安全组规则和 veth 之类开销,只有 ipvs 转发逻辑的 service 实现。socket bpf 在所有性能指标上,均有不同程度提升。大量并发的短连接,基本上吞吐提升 15%,时延降低 20%。
继续演进ebpf does to linux what javascript does to html.-- brendan gregg
基于 socket ebpf 实现的 service,大大简化了负载均衡的逻辑实现,充分体现了 ebpf 灵活、小巧的特点。ebpf 的这些特点也很契合云原生场景,目前,该技术已在阿里云展开实践,加速了 kubernetes 服务网络。我们会继续探索和完善更多的 ebpf 的应用案例,比如 ipv6、network policy 等。
华为举办鸿蒙生态千帆启航仪式,余承东公布HarmonyOS NEXT开放申请
紫外线水消毒领域的标准是什么
华为申请“HICAR 情感机器人”商标
助推车联网加速发展,芯讯通模组荣获年度最佳创新产品奖
安全光栅的组成
eBPF技术应用云原生网络实践系列之基于socket的service
ViTrox的托盘到磁带和卷盘视觉检测处理器升级
长沙经济开发区以新技术与新平台统领产业智能化转型升级
整流桥是怎么把交流电变成直流电的呢?
有线电视CATV网络中光分路器的设计
如何使用中继组网功能?
自适应比特率( ABR )缩放和高密度转码的挑战与解决方案
格科微12英寸CMOS图像传感器晶圆厂投产
我国8月份制造业总体运行情况分析
东芝发布可监测会话量和用餐时间的腕带式人体传感器
松下、IBM等加入智能电视联盟,平衡行业状态
三星Galaxy Note 3触控按键采用赛普拉斯CapSense控制器
自动语音播放电路原理
计算机硬盘检测无法通过的简易解决方法
STM32U5系列MCU上新:提高物联网和嵌入式应用性能和能效