eBPF技术应用云原生网络实践系列之基于socket的service | 龙蜥技术
简介:如何使用 socket eBPF进一步提升Service 网络的转发性能?
背景介绍
Kubernetes 中的网络功能,主要包括 POD 网络,service 网络和网络策略组成。其中 POD 网络和网络策略,都是规定了模型,没有提供默认实现。而 service 网络作为 Kubernetes 的特色部分,官方版本持续演进了多种实现:
在 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_CREATE
BPF_CGROUP_INET4_BIND
BPF_CGROUP_INET4_CONNECT
BPF_CGROUP_UDP4_SENDMSG
BPF_CGROUP_UDP4_RECVMSG
BPF_CGROUP_GETSOCKOPT
BPF_CGROUP_INET4_GETPEERNAME
BPF_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%。
转发性能比较(QPS)
90%转发延时比较(ms)
继续演进
eBPF does to Linux what JavaScript does to HTML.-- Brendan Gregg
基于 socket eBPF 实现的 service,大大简化了负载均衡的逻辑实现,充分体现了 eBPF 灵活、小巧的特点。eBPF 的这些特点也很契合云原生场景,目前,该技术已在阿里云展开实践,加速了 kubernetes 服务网络。我们会继续探索和完善更多的 eBPF 的应用案例,比如 IPv6、network policy 等。
本文为阿里云原创内容,未经允许不得转载。
eBPF技术应用云原生网络实践系列之基于socket的service | 龙蜥技术的更多相关文章
- Kube-OVN:大型银行技术团队推荐的金融级云原生网络方案
近日,由TWT社区主办的2021容器云职业技能大赛团队赛的冠军作品:<适用于大中型银行的云原生技术体系建设方案>中,Kube-OVN成为银行技术团队推荐的金融级云原生网络最佳实践.本文部分 ...
- 技术分享 | 云原生多模型 NoSQL 概述
作者 朱建平,TEG/云架构平台部/块与表格存储中心副总监.08年加入腾讯后,承担过对象存储.键值存储,先后负责过KV存储-TSSD.对象存储-TFS等多个存储平台. NoSQL 技术和行业背景 No ...
- 云原生网络代理(MOSN)的进化之路
本文系云原生应用最佳实践杭州站活动演讲稿整理.杭州站活动邀请了 Apache APISIX 项目 VP 温铭.又拍云平台开发部高级工程师莫红波.蚂蚁金服技术专家王发康.有赞中间件开发工程师张超,分享云 ...
- “行业客户云原生最佳实践日” 亮相KubeCon上海
2018年11月13日至15日,由CNCF主办的KubeCon + CloudNativeCon将首次登陆中国上海,这是全球范围内规模最大的Kubernetes和云原生技术盛会. 唯一聚焦客户实践的分 ...
- 灵雀云发布云原生制品仓库Harbor企业版(Alauda Registry Service for Harbor)
灵雀云发布云原生制品仓库Harbor企业版(Alauda Registry Service for Harbor) 近日,国内领先的云原生全栈私有云提供商灵雀云宣布,推出企业版云原生制品仓库Ala ...
- 《Kubernetes与云原生应用》系列之容器设计模式
http://www.infoq.com/cn/articles/kubernetes-and-cloud-native-app-container-design-pattern <Kubern ...
- 阿里云 CDN 业务基于边缘容器的云原生转型实践
导读:本文基于边缘容器的阿里云 CDN 云原生实践, 涵盖了边缘容器的背景和趋势,边缘托管集群 ACK Managed Edge K8s(文中简称“Edge@ACK”) 的能力.架构,以及基于边缘容器 ...
- 云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第1篇
项目初探 项目地址: 原项目:https://github.com/lonng/nanoserver 调过的:https://github.com/Kirk-Wang/nanoserver 这将是一个 ...
- 敢为人先,从阿里巴巴云原生团队实践Dapr案例,看分布式应用运行时前景
背景 Dapr是一个由微软主导的云原生开源项目,国内云计算巨头阿里云也积极参与其中,2019年10月首次发布,到今年2月正式发布V1.0版本.在不到一年半的时间内,github star数达到了1.2 ...
- Sentry 后端云原生中间件实践 ClickHouse PaaS ,为 Snuba 事件分析引擎提供动力
目录(脑图) ClickHouse PaaS 云原生多租户平台(Altinity.Cloud) 官网:https://altinity.cloud PaaS 架构概览 设计一个拥有云原生编排能力.支持 ...
随机推荐
- JSF+EJB+JPA之整体思想
序言: JSF+EJB+JPA 其实没有想象中的难,不过要做好应用以及在合适的地方建立应用,才是真正的难点. 好的技术在不合适的地方做了应用,那也只能是垃圾. 所以这个东西并不适合于太小规模的企业应用 ...
- Kotlin 协程基础使用学习
原文: Kotlin 协程基础使用学习-Stars-One的杂货小窝 本篇阅读可能需要以下知识,否则可能阅读会有些困难 客户端开发基础(Android开发或JavaFx开发) Java多线程基础 ko ...
- MySQL系列:索引失效场景总结
相关文章 数据库系列:MySQL慢查询分析和性能优化 数据库系列:MySQL索引优化总结(综合版) 数据库系列:高并发下的数据字段变更 数据库系列:覆盖索引和规避回表 数据库系列:数据库高可用及无损扩 ...
- SQL奇遇记:解锁 SQL 的秘密
数据库基础 在我们探究SQL语言之旅的起点,首先要对数据库的核心理念有所了解.数据库在现代生活中无处不在,每次网购.网页浏览.即时通讯,都在产生数据.简单来说,数据库就是按一定数据结构组织.存储.管理 ...
- 记录--用js如何实现将手机号中间的几位数字变成****
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 今天,我们要实现一个很常见并且简单的功能:将手机号中间的几位数变成**** 这个功能其实很常见,比如我们微信的账号安全里面显示的手机号.掘 ...
- https://codeforces.com/gym/496432
ABC:略. D 枚举分的段数,然后扫一遍判断. E F G H
- windows系统设置状态栏时间显示读秒
windows系统设置状态栏时间显示读秒 要实现的效果如下图: 一.打开注册表 WIN+R输入[cmd]之后输入[regedit]回车 二.修改注册表 在注册表地址栏输入: HKEY_CURRENT_ ...
- Refresh 重构(Refactor)
最近在闲暇之余重(第)温(一..次)此书, 首先能感受到的, 无论你是新程序员还是老程序员, 这本书都已经不具备太多的可读性了. 由于本书成书年代久远, 那个时候软件行业还不够发达, 面向对象还没有被 ...
- #模拟#U137456 数字
题目 牛牛和他的小伙伴们高高兴兴的吃完了蛋糕,吃完蛋糕之后就到了牛牛和他的小伙伴们最喜欢的环节了--猜数 字, 这次是牛牛的生日,大家决定让牛牛来制定规则,由于牛牛的生日是4月7日,所以牛牛特别喜欢数 ...
- C# 继承、多态性、抽象和接口详解:从入门到精通
C# 继承 在 C# 中,可以将字段和方法从一个类继承到另一个类.我们将"继承概念"分为两类: 派生类(子类) - 从另一个类继承的类 基类(父类) - 被继承的类 要从一个类继承 ...