Linux eBPF解析

简介: 今天,我们来了解下 Linux 系统的革命性通用执行引擎-eBPF,之所以聊着玩意,因为它确实牛逼,作为一项底层技术,在现在的云原生生态领域中起着举足轻重的作用。截至目前,业界使用范围最广的 K8S CNI 网络方案 Calico 已宣布支持 eBPF,而作为第一个实现了Kube-Proxy 所有功能的 K8S 网络方案——Cilium 也是基于 eBPF 技术。因此,只有了解其底层机制,才能有助于更好、更易地融入容器生态中。

      今天,我们来了解下 Linux 系统的革命性通用执行引擎-eBPF,之所以聊着玩意,因为它确实牛逼,作为一项底层技术,在现在的云原生生态领域中起着举足轻重的作用。截至目前,业界使用范围最广的 K8S CNI 网络方案 Calico 已宣布支持 eBPF,而作为第一个实现了Kube-Proxy 所有功能的 K8S 网络方案——Cilium 也是基于 eBPF 技术。因此,只有了解其底层机制,才能有助于更好、更易地融入容器生态中。

      作为一种颠覆性技术,eBPF 最早出现在 3.18 内核中,eBPF 新的设计针对现代硬件进行了优化,所以 eBPF 生成的指令集比旧的 BPF 解释器生成的机器码执行得更快。扩展版本也增加了虚拟机中的寄存器数量,将原有的 2 个 32 位寄存器增加到 10 个 64 位寄存器。由于寄存器数量和宽度的增加,开发人员可以使用函数参数自由交换更多的信息,编写更复杂的程序。总之,这些改进使 eBPF 版本的速度比原来的 BPF 提高了 4 倍。

       基于原本的想法,eBPF 实现的最初目标是优化处理网络过滤器的内部 BPF 指令集。然而,作为 BPF 技术的转折点,eBPF 已开始扩展至用户空间。使得 eBPF 不再局限于网络栈,已经成为内核顶级的子系统。eBPF 程序架构强调安全性和稳定性,看上去更像内核模块,但与内核模块不同,eBPF 程序不需要重新编译内核,并且可以确保 eBPF 程序运行完成,而不会造成系统的崩溃。

      具体参考如下示意图:

       eBPF 是一套通用执行引擎,提供了可基于系统或程序事件高效安全执行特定代码的通用能力,通用能力的使用者不再局限于内核开发者,除此之外,eBPF 可由执行字节码指令、存储对象和 Helper 帮助函数组成,字节码指令在内核执行前必须通过 BPF 验证器 Verfier 的验证,同时在启用 BPF JIT 模式的内核中,会直接将字节码指令转成内核可执行的本地指令运行。

      同时,eBPF 也逐渐在观测(跟踪、性能调优等)、安全和网络等领域发挥重要的角色。Facebook、NetFlix 、CloudFlare 等知名互联网公司内部广泛采用基于 eBPF 技术的各种程序用于性能分析、问题排查、负载均衡、DDoS 攻击预防等等,据相关信息显示在 Facebook 的机器上内置一系列基于 eBPF 的相关工具集。

      相对于系统的性能分析和观测,eBPF 技术在网络技术中的表现,更为抢眼,BPF 技术与 XDP(eXpress Data Path) 和 TC(Traffic Control) 组合可以实现功能更加强大的网络功能,更可为 SDN 软件定义网络提供基础支撑。XDP 只作用与网络包的 Ingress 层面,BPF 钩子位于网络驱动中尽可能早的位置,无需进行原始包的复制就可以实现最佳的数据包处理性能,挂载的 BPF 程序是运行过滤的理想选择,可用于丢弃恶意或非预期的流量、进行 DDOS 攻击保护等场景;而 TC Ingress 比 XDP 技术处于更高层次的位置,BPF 程序在 L3 层之前运行,可以访问到与数据包相关的大部分元数据,是本地节点处理的理想的地方,可以用于流量监控或者 L3/L4 的端点策略控制,同时配合 TC egress 则可实现对于容器环境下更高维度和级别的网络结构。关于 XDP 技术架构,可参考如下结构示意图:

      基于 Linux 系统生态体系,eBPF 有着得天独厚的优势,高效、生产安全且内核中内置,特别的可以在内核中完成数据分析聚合比如直方图,与将数据发送到用户空间分析聚合相比,能够节省大量的数据复制传递带来的 CPU 消耗。在解析 eBPF 之前,首先,我们先看下BPF 架构示意图,具体如下所示:

      接下来基于上述架构图,我们可以清晰的看到,BPF 主要工作在内核层,其本质是类 Unix 系统上数据链路层的一种原始接口,提供原始链路层封包的收发。BPF 在数据包过滤上引入了两大革新:

  • 全新的虚拟机 (VM) 设计模型,能够有效地工作在基于寄存器结构的 CPU 之上
  • 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息。这样可以最大程度地减少BPF 处理的数据量

      基于这些巨大的改进,目前,几乎所有的 (类)Unix 系统都选择采用 BPF 作为网络数据包过滤技术,直到今天,许多 Unix 内核的派生系统中(包括 Linux 内核)仍基于此实现方式。举个简单的示例,Linux 操作系统上的 Tcpdump 底层采用的就是 BPF 作为包过滤技术。

      接下来,们再了解下 eBPF 的整体架构,具体如下图所示:

      基于上述架构图,我们可以看到,整个 eBPF 主要分为 2 部分组件:User Program (用户空间程序)和 Kernel (内核程序)。针对两部分组件,简要介绍如下:

      User Program (用户空间程序):负责加载 BPF 字节码至内核,基于特殊场景需求,也可能需要负责读取内核回传的统计信息或者事件详情。

      Kernel (内核程序):内核中的 BPF 字节码负责在内核中执行特定事件,基于特定场景需要,也会将执行的结果通过 Maps 或者 Perf-Event 事件发送至用户空间。

      在此架构参考示意图中,用户空间程序与内核 BPF 字节码程序可以基于 Map 结构实现双向通信,这为内核中运行的 BPF 字节码程序提供了更加灵活的控制。

      我们再看下 User Program (用户空间程序)与 Kernel (内核程序)的 BPF 字节码交互的流程,具体如下所示:

      1、在User Program (用户空间程序)中,基于LLVM 或者 GCC 工具将编写的 BPF 代码程序编译成 BPF 字节码

      2、使用加载程序 Loader 将字节码加载至内核,内核使用验证器(Verfier) 组件保证执行字节码的安全性,以避免对内核造成灾难,在确认字节码安全后将其加载对应的内核模块执行;BPF 观测技术相关的程序类型可能是 Kprobes/Uprobes/Tracepoint/Perf_events 中的一个或多个。

      针对 BPF 相关的程序类型进行简要解析,具体如下:

      Kprobes:实现内核中动态跟踪。Kprobes 可以跟踪到 Linux 内核中的导出函数入口或返回点,但是不是稳定 ABI 接口,可能会因为内核版本变化导致,导致跟踪失效。

      Uprobes用户级别的动态跟踪。与 Kprobes 类似,只是跟踪用户程序中的函数。

     Tracepoints内核中静态跟踪。tracepoints 是内核开发人员维护的跟踪点,能够提供稳定的 ABI 接口,但是由于是研发人员维护,数量和场景可能受限。

      Perf_events定时采样和 PMC。

     3、内核中运行的 BPF 字节码程序可以使用两种方式将测量数据回传至用户空间,具体,Maps 方式可用于将内核中实现的统计摘要信息(比如测量延迟、堆栈信息)等回传至用户空间;Perf-event 则用于将内核采集的事件实时发送至用户空间,用户空间程序实时读取分析。

      从本质上来讲,eBPF 催生了一种全新的软件开发方式。基于这种方式,我们不仅能够对内核行为进行编程,而且依据场景需求还能编写跨多个子系统的处理逻辑,而传统上这些子系统是完全独立、 无法用一套逻辑来处理的。

      当前,市面上eBPF 相关的知名的开源项目包括但不限于以下:

      1、Facebook 高性能 4 层负载均衡器 Katran。

      2、Cilium 为下一代微服务 ServiceMesh 所打造的具备 API 感知和安全高效的容器网络方案,底层主要使用 XDP 和 TC 等相关技术。

      3、CloudFlare 公司开源的 eBPF Exporterbpf-toolseBPF Exporter 将 eBPF 技术与监控 Prometheus 紧密结合起来,而bpf-tools 可用于网络问题分析和排查。

      4、IO Visor 项目开源的 BCC、 BPFTrace 和 Kubectl-Trace:BCC 提供了更高阶的抽象,可以让用户采用 Python、C++ 和 Lua 等高级语言快速开发 BPF 程序;BPFTrace 采用类似于 awk 语言快速编写 eBPF 程序;Kubectl-Trace 则提供了在 kubernetes 集群中使用 BPF 程序调试的方便操作。

      由于 eBPF 还在快速发展期,内核中的功能也日趋增强及完善,因此,在实际的业务场景中,我们一般推荐基于 Linux 4.4+  (4.9 以上效能会更佳) 内核的来使用 eBPF。部分 Linux Event 和 BPF 版本支持见下图:    


      除上述较为知名的 eBPF 相关的开源项目外,还有越来越多的新兴项目如雨后脆笋一样开始蓬勃发展,并逐步在各种社区布局、开发以及优化完善,成为一股暖流,冲向广阔的市场。

      接下来,我们针对 eBPF 所涉及的各方面进行简要解析,主要从网络、安全、性能追踪以及观测及监控等4个维度进行,具体如下所示。

网络

     其实,刚才前面针对网络这部分已经有所描述,现在对其进行简要概括,具体,eBPF 的两大特色:可编程和高性能,使它能满足所有的网络包处理需求。可编程意味着无需离开内核中的包处理上下文,就能添加额外的协议解析器或任何转发逻辑, 以满足不断变化的需求。高性能的 JIT 编译器使 eBPF 程序能达到几乎与原生编译的内核态代码一样的执行性能。

安全

      eBPF 能够观测和理解所有的系统调用的能力,以及在 Packet 层和 Socket 层审视所有的网络操作的能力,基于此两者相结合,为系统安全提供了革命性的新思路。在此革命未发生之前,传统模式是基于系统调用过滤、网络层过滤和进程上下文跟踪是在完全独立的系统中完成的,而 eBPF 的出现则统一了可观测性和各层面的控制能力,使得我们有更加丰富的上下文和更精细的控制能力, 因而能创建更加安全的系统。

性能追踪

      eBPF 程序能够加载到 Trace points、内核及用户空间应用程序中的 Probe points, 这种能力使我们对应用程序的运行时行为(Runtime Behavior)和系统本身 (System Itself)提供了史无前例的可观测性。应用端和系统端的这种观测能力相结合, 能在排查系统性能问题时提供强大的能力和独特的信息。BPF 使用了很多高级数据结构, 因此能非常高效地导出有意义的可观测数据,而不是像很多同类系统一样导出海量的原始采样数据。

观测及监控

     相比于操作系统提供的静态计数器(Counters、Gauges),eBPF 能在内核中收集和聚合自定义 Metric, 并能从不同数据源来生成可观测数据。这既扩展了可观测性的深度,也显著减少了整体系统开销, 因为现在可以选择只收集需要的数据,并且后者是直方图或类似的格式,而非原始采样数据。

     上面讲述了 eBPF 的相关特性以及优点,最后,我们再了解下在基于当前的技术以及业务场景下,eBPF 应用的局限性,具体如下:

      1、现有的环境下,eBPF 程序不能调用任意的内核参数,只限于内核模块中列出的 BPF Helper 函数。

      2、eBPF 字节码大小最初被限制为 4096 条指令,截止到内核 Linux 5.8 版本, 当前已将放宽至 100 万指令( BPF_COMPLEXITY_LIMIT_INSNS),可参考源码所示:include/linux/bpf.h,对于无权限的BPF程序,仍然保留 4096 条限制 ( BPF_MAXINSNS );新版本的 eBPF 也支持了多个 eBPF 程序级联调用,虽然传递信息存在某些限制,但是可以通过组合实现更加强大的功能。

      3、eBPF 堆栈大小被限制在 MAX_BPF_STACK,截止到内核 Linux 5.8 版本,被设置为 512;可参考源码所示: include/linux/filter.h,这个限制特别是在栈上存储多个字符串缓冲区时:一个char[256]缓冲区会消耗这个栈的一半。目前没有计划增加这个限制,解决方法是改用 bpf 映射存储,它实际上是无限的。

      4、eBPF 程序不允许包含无法到达的指令,防止加载无效代码,延迟程序的终止。

      5、eBPF 程序中循环次数限制且必须在有限时间内结束,这主要是用来防止在 kprobes 中插入任意的循环,导致锁住整个系统;解决办法包括展开循环,并为需要循环的常见用途添加辅助函数。Linux 5.3 在 BPF 中包含了对有界循环的支持,它有一个可验证的运行时间上限。

      综上所述,虽然 eBPF 技术在当前的环境下影响力强大,但是为了保证内核的处理安全和及时响应,内核中的 eBPF 技术也被进行着诸多的限制,或许,随着技术的发展和内核演进,基于 eBPF,我们可能会找出一个更为性价比的综合解决方案。


相关实践学习
CentOS 8迁移Anolis OS 8
Anolis OS 8在做出差异性开发同时,在生态上和依赖管理上保持跟CentOS 8.x兼容,本文为您介绍如何通过AOMS迁移工具实现CentOS 8.x到Anolis OS 8的迁移。
相关文章
|
2月前
|
Ubuntu Linux
"unzip"命令解析:Linux下如何处理压缩文件。
总的来说,`unzip`命令是Linux系统下一款实用而方便的ZIP格式文件处理工具。本文通过简明扼要的方式,详细介绍了在各类Linux发行版上安装 `unzip`的方法,以及如何使用 `unzip`命令进行解压、查看和测试ZIP文件。希望本文章能为用户带来实际帮助,提高日常操作的效率。
286 12
|
2月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
72 20
|
3月前
|
Linux
Linux命令的基本格式解析
总的来说,Linux命令的基本格式就像一个食谱,它可以指导你如何使用你的计算机。通过学习和实践,你可以成为一个真正的“计算机厨师”,创造出各种“美味”的命令。
93 15
|
3月前
|
存储 Linux
Linux内核中的current机制解析
总的来说,current机制是Linux内核中进程管理的基础,它通过获取当前进程的task_struct结构的地址,可以方便地获取和修改进程的信息。这个机制在内核中的使用非常广泛,对于理解Linux内核的工作原理有着重要的意义。
141 11
|
4月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
6月前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
202 11
|
6月前
|
存储 运维 安全
深入解析操作系统控制台:阿里云Alibaba Cloud Linux(Alinux)的运维利器
本文将详细介绍阿里云的Alibaba Cloud Linux操作系统控制台的功能和优势。
228 6
|
8月前
|
缓存 并行计算 Linux
深入解析Linux操作系统的内核优化策略
本文旨在探讨Linux操作系统内核的优化策略,包括内核参数调整、内存管理、CPU调度以及文件系统性能提升等方面。通过对这些关键领域的分析,我们可以理解如何有效地提高Linux系统的性能和稳定性,从而为用户提供更加流畅和高效的计算体验。
281 24
|
8月前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
149 4
|
8月前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####