Linux

ebpf

December 24, 2021
Linux
Ebpf

ebpf: 扩展伯克利包过滤器。

下面的内容主要来源于 译文

用处 #

目前,主要有两大组触发器。

第一组用于处理网络数据包和管理网络流量。它们是 XDP、流量控制事件及其他几个事件。

以下情况需要用到这些事件:

创建简单但非常有效的防火墙。Cloudflare 和 Facebook 等公司使用 BPF 程序来过滤掉大量的寄生流量,并打击最大规模的 DDoS 攻击。由于处理发生在数据包生命的最早阶段,直接在内核中进行(BPF 程序的处理有时甚至可以直接推送到网卡中进行),因此可以通过这种方式处理巨量的流量。这些事情过去都是在专门的网络硬件上完成的。

创建更智能、更有针对性、但性能更好的防火墙——这些防火墙可以检查通过的流量是否符合公司的规则、是否存在漏洞模式等。例如,Facebook 在内部进行这种审计,而一些项目则对外销售这类产品。

创建智能负载均衡器。最突出的例子就是 Cilium 项目,它最常被用作 K8s 集群中的网格网络。Cilium 对流量进行管理、均衡、重定向和分析。所有这些都是在内核运行的小型 BPF 程序的帮助下完成的,以响应这个或那个与网络数据包或套接字相关的事件。

这是第一组与网络问题相关并能够影响网络通信行为的触发器。第二组则与更普遍的可观察性相关;在大多数情况下,这组的程序无法影响任何事件,而只能“观察”。这才是我更感兴趣的。

这组的触发器有如下几个:

perf 事件(perf events)——与性能和 perf Linux 分析器相关的事件:硬件处理器计数器、中断处理、小 / 大内存异常拦截等等。例如,我们可以设置一个处理程序,每当内核需要从 swap 读取内存页时,该处理程序就会运行。例如,想象有这样一个实用程序,它显示了当前所有使用 swap 的程序。

跟踪点(tracepoints)——内核源代码中的静态(由开发人员定义)位置,通过附加到这些位置,你可以从中提取静态信息(开发人员先前准备的信息)。在这种情况下,静态似乎是一件坏事,因为我说过,日志的缺点之一就是它们只包含了程序员最初放在那里的内容。从某种意义上说,这是正确的,但跟踪点有三个重要的优势:

有相当多的跟踪点散落在内核中最有趣的地方

当它们不“开启”时,它们不使用任何资源

它们是 API 的一部分,它们是稳定的,不会改变。这非常重要,因为我们将提到的其他触发器缺少稳定的 API。

例如,假设有一个关于显示的实用程序,内核出于某种原因没有给它时间执行。你坐着纳闷为什么它这么慢,而 pprof 却没有显示任何什么有趣的东西。

USDT——与跟踪点相同,但是它适用于用户空间的程序。也就是说,作为程序员,你可以将这些位置添加到你的程序中。并且许多大型且知名的程序和编程语言都已经采用了这些跟踪方法:例如 MySQL、或者 PHP 和 Python 语言。通常,它们的默认设置为“关闭”,如果要打开它们,需要使用 enable-dtrace 参数或类似的参数来重新构建解释器。是的,我们还可以在 Go 中注册这种类跟踪。你可能已经识别出参数名称中的单词 DTrace。关键在于,这些类型的静态跟踪是由 Solaris) 操作系统中诞生的同名系统所推广的。例如,想象一下,何时创建新线程、何时启动 GC 或与特定语言或系统相关的其他内容,我们都能够知道是怎样的一种场景。

这是另一种魔法开始的地方:

Ftrace 触发器为我们提供了在内核的任何函数开始时运行 BPF 程序的选项。这是完全动态的。这意味着内核将在你选择的任何内核函数或者在所有内核函数开始执行之前,开始执行之前调用你的 BPF 函数。你可以连接到所有内核函数,并在输出时获取所有调用的有吸引力的可视化效果。

...

linux epoll

July 17, 2021
Linux
Epoll

linux epoll #

wiki

手册

why #

what #

Linux内核的可扩展I/O事件通知机制

于Linux 2.5.44首度登场,它设计目的旨在取代既有POSIX select(2)与poll(2)系统函数,让需要大量操作文件描述符的程序得以发挥更优异的性能(举例来说:旧有的系统函数所花费的时间复杂度为O(n),epoll的时间复杂度O(log n))。epoll 实现的功能与 poll 类似,都是监听多个文件描述符上的事件。

how #

epoll 通过使用红黑树(RB-tree)搜索被监控的文件描述符(file descriptor)。

在 epoll 实例上注册事件时,epoll 会将该事件添加到 epoll 实例的红黑树上并注册一个回调函数,当事件发生时会将事件添加到就绪链表中。

int epoll_create(int size);

在内核中创建epoll实例并返回一个epoll文件描述符。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

向 epfd 对应的内核epoll 实例添加、修改或删除对 fd 上事件 event 的监听。op 可以为 EPOLL_CTL_ADD, EPOLL_CTL_MOD, EPOLL_CTL_DEL 分别对应的是添加新的事件,修改文件描述符上监听的事件类型,从实例上删除一个事件。如果 event 的 events 属性设置了 EPOLLET flag,那么监听该事件的方式是边缘触发。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

当 timeout 为 0 时,epoll_wait 永远会立即返回。而 timeout 为 -1 时,epoll_wait 会一直阻塞直到任一已注册的事件变为就绪。当 timeout 为一正整数时,epoll 会阻塞直到计时 timeout 毫秒终了或已注册的事件变为就绪。因为内核调度延迟,阻塞的时间可能会略微超过 timeout 毫秒。

...