佳能|一文详解用 eBPF 观测 HTTP( 二 )


TCP与eBPF 由于本文观测协议HTTP 1、HTTP1.1以及HTTP2 都是基于TCP 模型 , 所以先回顾一下 TCP 建立连接的过程 。 首先Client 端通过3次握手建立通信 , 从TCP协议上来说 , 连接代表着状态信息 , 比如包含seq、ack、窗口/buffer等 , 而tcp握手就是协商出来这些初始值;而从操作系统的角度来说 , 建立连接后 , TCP 创建了INET域的 socket , 同时也占用了FD 资源 。 对于四次挥手 , 从TCP协议上来说 , 可以理解为释放终止信号 , 释放所维持的状态;而从操作系统的角度来说 , 四次挥手后也意味着Socket FD 资源的回收 。
而对于应用层的角度来说 , 还有一个常用的概念 , 这就是长连接 , 但长连接对于TCP传输层来说 , 只是使用方式的区别:
应用层短连接:三次握手+单次传输数据+四次挥手 , 代表协议HTTP 1 应用层长连接:三次握手+多次传输数据+四次挥手 , 代表协议 HTTP 1.1、HTTP2

参考下图TCP 建立连接过程内核函数的调用 , 对于eBPF 程序可以很容易的定义好tracepoints/kprobe 切入点 。 例如建立连接过程可以切入 accept 以及connect 函数 , 释放链接过程可以切入close过程 , 而传输数据可以切入read 或write函数 。

基于TCP 大多数切入点已经被静态化为tracepoints , 因此BPF 程序定义如下切入点来覆盖上述提到的TCP 核心函数(sys_enter 代表进入时切入 , sys_exit 代表返回时切入) 。
SEC(\"tracepoint/syscalls/sys_enter_connect\") SEC(\"tracepoint/syscalls/sys_exit_connect\") SEC(\"tracepoint/syscalls/sys_enter_accept\") SEC(\"tracepoint/syscalls/sys_exit_accept\") SEC(\"tracepoint/syscalls/sys_enter_accept4\") SEC(\"tracepoint/syscalls/sys_exit_accept4\") SEC(\"tracepoint/syscalls/sys_enter_close\") SEC(\"tracepoint/syscalls/sys_exit_close\") SEC(\"tracepoint/syscalls/sys_enter_write\") SEC(\"tracepoint/syscalls/sys_exit_write\") SEC(\"tracepoint/syscalls/sys_enter_read\") SEC(\"tracepoint/syscalls/sys_exit_read\") SEC(\"tracepoint/syscalls/sys_enter_sendmsg\") SEC(\"tracepoint/syscalls/sys_exit_sendmsg\") SEC(\"tracepoint/syscalls/sys_enter_recvmsg\") SEC(\"tracepoint/syscalls/sys_exit_recvmsg\") ....
结合上述概念 , 我们以iLogtail的eBPF 工作模型为例 , 介绍一个可观测领域的eBPF 程序是如何真正工作的 。 更多详细内容可以参考此分享: 基于eBPF的应用可观测技术实践 。 如下图所示 , iLogtaileBPF 程序的工作空间分为Kernel Space与User Space 。
Kernel Space 主要负责数据的抓取与预处理:
抓取:Hook模块会依据KProbe定义拦截网络数据 , 虚线中为具体的KProbe 拦截的内核函数(使用上述描述的SEC进行定义) , 如connect、accept 以及write 等 。预处理:预处理模块会根据用户态配置进行数据的拦截丢弃以及数据协议的推断 , 只有符合需求的数据才会传递给SendToUserSpace模块 , 而其他数据将会被丢弃 。 其后SendToUserSpace 模块通过eBPF Map 将过滤后的数据由内核态数据传输到用户态 。User Space 的模块主要负责数据分析、聚合以及管理:
分析:Process 模块会不断处理eBPF Map中存储的网络数据 , 首先由于Kernel 已经推断协议类型 , Process 模块将根据此类型进行细粒度的协议分析 , 如分析MySQL 协议的SQL、分析HTTP 协议的状态码等 。 其次由于 Kernel 所传递的连接元数据信息只有Pid 与 FD 等进程粒度元信息 , 而对于Kubernetes 可观测场景来说 , Pod、Container 等资源定义更有意义 , 所以Correlate Meta 模块会为Process 处理后的数据绑定容器相关的元数据信息 。聚合:当绑定元数据信息后 , Aggreate 模块会对数据进行聚合操作以避免重复数据传输 , 比如聚合周期内某SQL 调用1000次 , Aggreate 模块会将最终数据抽象为 XSQL:1000 的形式进行上传 。管理:整个eBPF 程序交互着大量着进程与连接数据 , 因此eBPF 程序中对象的生命周期需要与机器实际状态相符 , 当进程或链接释放 , 相应的对象也需要释放 , 这也正对应着Connection Management 与Garbage Collection 的职责 。