eBPF 程序开发入门:从原理到生产级工具构建

概述 eBPF(Extended Berkeley Packet Filter)是 Linux 内核领域近十年来最具革命性的技术之一。它允许开发者在不修改内核源代码、不加载内核模块的前提下,安全高效地在内核空间运行自定义程序。从网络包过滤到系统调用追踪、从性能分析到安全审计,eBPF 已经成为现代可观测性和网络数据面的基石。 我将从 eBPF 的基本原理出发,逐步深入到开发环境搭建、程序类型选择、BCC 与 libbpf+CO-RE 的工程对比,最后给出一个完整的生产级 eBPF 工具开发流程。适合有一定 Linux 内核基础的 SRE 工程师和系统开发者阅读。 一、eBPF 的演进:从 BPF 到 eBPF 1.1 经典 BPF(cBPF) 1992 年,Steven McCanne 和 Van Jacobson 在论文《The BSD Packet Filter: A New Architecture for User-level Capture》中提出了 BPF。其核心思想是将一个基于寄存器的虚拟机嵌入内核,允许用户将过滤程序注入内核空间,只有匹配的网络包才会被复制到用户态,从而大幅减少不必要的上下文切换开销。 经典 BPF 的局限性很明显: 特性 cBPF eBPF 寄存器数量 2 个 32 位 11 个 64 位 指令集 简单,仅支持包过滤 丰富,支持函数调用、64 位运算 程序大小 严格限制(4096 指令) 百万级指令(经验证器检查) 挂载点 仅网络包 系统调用、内核函数、跟踪点、网络等 安全机制 基本检查 验证器 + JIT 编译 1....

April 1, 2025 · 13 分钟 · 2562 字 · 徐保金

Linux 防火墙:iptables/nftables 入门与实践

概述 Linux 防火墙经历了从 ipfwadm → ipchains → iptables → nftables 的演进。底层均基于 Netfilter 框架,但上层语法和管理方式不断改进。从 Netfilter 架构出发,深入 iptables 的五链四表、nftables 的优势与用法、NAT/端口转发、连接追踪机制以及生产环境的性能优化实践。 Netfilter 框架 架构概览 Netfilter 是 Linux 内核中的数据包处理框架,通过在内核网络栈的关键位置挂载钩子(hook)来实现数据包过滤、地址转换、连接追踪等功能。 Netfilter 钩子点 [数据包进入] → PREROUTING → [路由判断] →─┬─→ FORWARD → POSTROUTING → [数据包发出] │ └─→ INPUT → [本地进程] → OUTPUT → POSTROUTING → [数据包发出] 五大钩子点 钩子点 触发时机 中文含义 NF_INET_PRE_ROUTING 数据包进入网络栈,路由前 路由前 NF_INET_LOCAL_IN 数据包目的地是本机 输入 NF_INET_FORWARD 数据包需要转发到其他接口 转发 NF_INET_LOCAL_OUT 本机产生的数据包 输出 NF_INET_POST_ROUTING 数据包即将离开网络栈 路由后 数据包流向 入站(访问本机): NIC → PREROUTING → INPUT → 本机进程 出站(本机发出): 本机进程 → OUTPUT → POSTROUTING → NIC 转发(经过本机): NIC → PREROUTING → FORWARD → POSTROUTING → NIC iptables 五链四表 四张表 iptables 通过"表"来组织不同功能的规则链:...

January 10, 2025 · 13 分钟 · 2596 字 · 徐保金

Linux 性能分析利器:BPF 与 bcc 工具集

eBPF:内核可编程的革命 传统性能分析工具分两类:一类是 top、vmstat、iostat 这样的"概览型"工具,告诉你系统层面发生了什么,但看不到细节;另一类是 strace、gdb 这样的"跟踪型"工具,能看细节但开销巨大,生产环境基本不敢用。 eBPF(Extended Berkeley Packet Filter)改变了一切。它允许你在不修改内核源码、不加载内核模块的前提下,安全地在内核中运行沙箱程序。这些程序挂载到内核的 hook 点(kprobes、tracepoints、perf events 等),在事件发生时被触发执行,采集数据后通过 ring buffer 传递到用户态。 为什么说这是革命性的?三个原因: 安全:eBPF 程序在加载时经过验证器(verifier)检查,确保不会死循环、不会非法访问内存,不需要 root 权限加载内核模块的风险。 低开销:eBPF 程序在内核态直接执行,只有采集到的数据才通过 ring buffer 拷贝到用户态,热路径上的开销极小。 可编程:你可以针对自己的具体问题编写精确的探针程序,而不是依赖通用工具"凑合"用。 eBPF 的完整技术文档可参考 BPF Compiler Collection (BCC) 官方仓库,本文所有工具均来自该项目。 bcc 工具集安装 bcc(BPF Compiler Collection)是基于 eBPF 的性能分析工具集,由 iovisor 项目维护,提供了数十个开箱即用的追踪工具。 Ubuntu / Debian # Ubuntu 20.04+ 推荐方式 sudo apt update sudo apt install -y bpfcc-tools linux-headers-$(uname -r) # 验证安装 /usr/share/bcc/tools/biolatency --help CentOS / RHEL # CentOS 8 / RHEL 8+ sudo dnf install -y bcc-tools kernel-devel-$(uname -r) # CentOS 7 需通过 ELRepo sudo yum install -y epel-release sudo yum install -y bcc-tools kernel-devel-$(uname -r) # 工具默认安装在 /usr/share/bcc/tools/ 目录下 ls /usr/share/bcc/tools/ 安装后建议将工具路径加入 PATH:...

November 13, 2024 · 5 分钟 · 953 字 · 徐保金

cgroup v2 完全指南:从架构原理到生产实践

概述 在云原生和容器化技术全面普及的今天,Linux cgroup(控制组)作为资源隔离和限制的内核基石,其重要性不言而喻。从 Docker 容器的内存限制到 Kubernetes Pod 的 CPU Requests/Limits,底层都依赖 cgroup 机制。然而,cgroup v1 的多层级架构、控制器行为不一致、线程模型混乱等历史包袱,让运维人员在生产环境中频频踩坑。 cgroup v2 作为对 v1 的彻底重构,采用单一层级树(unified hierarchy)架构,从根本上解决了 v1 的设计缺陷。自 Linux 4.5 引入以来,经过多个内核版本的迭代完善,cgroup v2 在 5.x 内核上已趋于成熟稳定。Ubuntu 22.04+、RHEL 9+、Debian 12+ 等主流发行版已默认使用 cgroup v2,Docker 和 Kubernetes 也已全面支持。 我将从 cgroup v2 的架构原理出发,深入讲解核心控制器的工作机制,结合 systemd 集成、Docker 容器限制、Kubernetes 场景等实战配置,最后覆盖 v1 到 v2 的迁移策略,帮助你在生产环境中驾驭这一关键技术。 cgroup v1 vs v2:为什么要重构 v1 的核心痛点 cgroup v1 在设计之初,每个控制器可以独立挂载在不同的层级树上。这带来了灵活性,但也埋下了大量隐患: 问题维度 v1 表现 影响 多层级架构 每个控制器可挂载在独立的层级树 进程在不同控制器中可属于不同 cgroup,管理视图割裂 线程模型 进程的线程可分散到不同 cgroup 资源计量混乱,难以准确归因 控制器间协调 各控制器独立运作 无法做跨资源的统一策略(如 CPU 和内存的联动) 委派安全 子 cgroup 委派权限粗粒度 容器逃逸风险,安全边界模糊 接口一致性 不同控制器文件命名和语义不统一 运维认知负担高,脚本维护困难 v2 的设计哲学 cgroup v2 的核心设计原则是单一层级树(unified hierarchy):整个系统只有一棵 cgroup 树,所有控制器挂载在同一棵树上。一个进程只属于一个 cgroup,该 cgroup 上可以同时启用 CPU、内存、IO 等多个控制器。...

July 23, 2024 · 17 分钟 · 3430 字 · 徐保金

Linux 进程调度器:CFS 原理与调优

概述 进程调度器是操作系统内核的核心组件,它决定了哪个进程在哪个 CPU 上运行、运行多长时间。Linux 自 2.6.23 起采用 CFS(Completely Fair Scheduler)作为默认调度器,经过多年演进,在 6.6 内核中又引入了 EEVDF(Earliest Eligible Virtual Deadline First)替代 CFS。本文深入理解 CFS 的工作原理、nice/cgroup CPU 控制、实时调度、CPU 亲和性等核心主题,并分享生产环境的调优经验。 CFS 调度器原理 设计哲学 CFS 的核心目标是"完全公平"——每个进程按照其权重比例获得 CPU 时间。与传统调度器基于时间片不同,CFS 使用"虚拟运行时间"(vruntime)来跟踪每个进程的 CPU 消耗: vruntime = 实际运行时间 × (NICE_0_LOAD / 进程权重) nice 值为 0 的进程权重为 1024(NICE_0_LOAD) nice 值越低,权重越大,vruntime 增长越慢,获得更多 CPU 时间 CFS 始终选择 vruntime 最小的进程运行 红黑树与调度队列 CFS 使用红黑树维护运行队列,按 vruntime 排序: [vruntime=50] / \ [vruntime=20] [vruntime=80] / \ [vruntime=10] [vruntime=35] 最左节点(vruntime 最小)是下一个被调度的进程 进程运行后 vruntime 增加,被重新插入红黑树 查找、插入、删除均为 O(log N) 调度周期与最小粒度 # 调度周期(目标延迟):所有进程在这段时间内至少运行一次 $ sysctl kernel....

May 29, 2024 · 7 分钟 · 1330 字 · 徐保金

Linux 内存管理机制与调优实战

概述 内存是 Linux 系统中最宝贵的资源之一。理解内核如何管理内存,不仅能帮助你定位 OOM、内存泄漏等线上故障,还能在容量规划和性能调优时做出更准确的决策。从虚拟内存模型出发,覆盖 Page Cache、Swap 策略、OOM Killer 原理、cgroup v2 内存限制、slab/shmem 调优等核心主题,并附带多个生产环境实战案例。 虚拟内存模型 地址空间分层 Linux 采用虚拟内存机制,每个进程拥有独立的虚拟地址空间: 层级 说明 用户态可见 用户空间 0x000000000000 ~ 0x00007FFFFFFFFFFF 是 非规范区 0x0000800000000000 ~ 0xFFFF7FFFFFFFFFFF 否(空洞) 内核空间 0xFFFF800000000000 ~ 0xFFFFFFFFFFFFFFFF 否 64 位系统下,用户空间理论上有 128TB(47 位地址),内核空间同样 128TB。实际可用受 TASK_SIZE 和 mm_struct 限制。 内存_zone 划分 内核将物理内存划分为多个 zone,不同 zone 有不同用途: $ cat /proc/zoneinfo | grep -E "^Node|pages free|high|normal|DMA" Zone 用途 典型场景 DMA 16MB 以下,旧 ISA 设备 DMA 几乎不用 DMA32 4GB 以下,32 位 DMA 设备 老硬件 Normal 4GB 以上,大多数内存分配 主要使用 Movable 可迁移页面,支持内存热插拔 虚拟化/大页 当 Normal zone 内存耗尽时,内核会从 DMA32 zone 借用页面(watermark 机制),但频繁借用会导致性能下降。...

May 9, 2024 · 8 分钟 · 1594 字 · 徐保金

Linux 网络栈调优:从内核到应用

为什么要调优 Linux 网络栈 Linux 内核默认的网络参数是为通用场景设计的,保守而安全。但在高并发 Web 服务、大规模负载均衡器、CDN 节点等场景下,默认值会成为瓶颈。典型症状包括: dmesg 出现 nf_conntrack: table full, dropping packet ss -s 显示大量 TIME-WAIT 连接 压测时 CPU 没跑满但吞吐量上不去 网卡 PPS(包每秒)远低于硬件能力 这些问题大多源于内核网络参数未调优。从协议栈参数、conntrack、网卡多队列、拥塞控制四个层面详细梳理。 内核网络参数的完整说明可参考 kernel.org 文档,本文涉及的参数在 Documentation/networking/ip-sysctl.txt 中有详细定义。 TCP/IP 协议栈关键内核参数 所有参数通过 sysctl 或 /proc/sys/net/ 查看和修改。以下参数均在 net.ipv4 命名空间下。 连接队列参数 # 查看当前值 sysctl net.ipv4.tcp_max_syn_backlog sysctl net.core.somaxconn sysctl net.core.netdev_max_backlog somaxconn — 监听套接字的全连接队列上限: # 默认值通常为 128 或 4096(取决于内核版本) # 高并发场景建议设置为 65535 net.core.somaxconn = 65535 全连接队列存放已完成三次握手但尚未被 accept() 取走的连接。队列满后新连接被丢弃,客户端看到连接超时。注意:应用层面的 listen(fd, backlog) 的 backlog 值不能超过 somaxconn,实际取两者最小值。...

May 7, 2024 · 7 分钟 · 1284 字 · 徐保金

Linux 启动流程详解:从固件到用户空间

概述 Linux 系统的启动是一个精密编排的多阶段过程,从固件加电自检到内核加载、再到用户空间服务启动,每个阶段都有其特定职责。理解完整的启动流程不仅有助于排查启动故障,还能进行启动性能优化。从固件层出发,逐层解析 BIOS/UEFI、GRUB2、initramfs、内核初始化、systemd 启动流程,并覆盖启动优化和内核崩溃恢复。 启动流程概览 [电源开启] │ ▼ [1. 固件阶段] BIOS / UEFI │ POST (加电自检) │ 硬件初始化 │ 查找启动设备 ▼ [2. 引导阶段] GRUB2 │ 加载 GRUB 到内存 │ 读取 grub.cfg │ 加载内核和 initramfs ▼ [3. 内核阶段] Linux Kernel │ 内核解压并初始化 │ 硬件检测和驱动加载 │ 挂载 initramfs │ 启动 init (systemd) ▼ [4. 用户空间阶段] systemd │ 读取 default.target │ 按依赖顺序启动服务 │ 启动登录服务 ▼ [5. 登录阶段] │ getty / display-manager │ 用户认证 │ Shell 启动 ▼ [系统就绪] BIOS 与 UEFI BIOS vs UEFI 特性 BIOS UEFI 启动模式 Legacy UEFI 固件接口 16位 32/64位 分区表 MBR (≤2TB) GPT (>2TB) 启动代码 512字节MBR EFI分区 启动速度 慢 快 网络功能 无 有(PXE/HTTP启动) 安全启动 不支持 支持 分辨率 文本模式 图形模式 BIOS 启动流程 1....

May 3, 2024 · 13 分钟 · 2586 字 · 徐保金

Linux 软件包管理:apt/yum/dnf 与包构建

概述 软件包管理是 Linux 系统运维的基础。Debian 系使用 apt/dpkg,Red Hat 系使用 yum/dnf/rpm。理解两套包管理体系的原理和用法,掌握仓库管理、依赖解析、包构建、版本锁定和离线安装,是高效运维的前提。本文系统对比两大体系,并深入实践包构建和镜像源优化。 apt/dpkg 体系 体系架构 apt (高级前端) │ ├── apt-get → 包安装/卸载/更新 ├── apt-cache → 包查询/搜索 └── apt → 综合命令(交互友好) │ dpkg (底层工具) │ ├── dpkg → .deb 包安装/卸载 ├── dpkg-deb → .deb 包操作 └── dpkg-query → 包查询 │ aptitude (替代前端,可选) apt vs apt-get # apt 是 apt-get 和 apt-cache 的综合,输出更友好 # 常用对照: # 安装 $ apt install nginx # 新(推荐交互使用) $ apt-get install nginx # 旧(推荐脚本使用) # 搜索 $ apt search nginx $ apt-cache search nginx # 查看包信息 $ apt show nginx $ apt-cache show nginx # 更新索引 $ apt update $ apt-get update # 升级 $ apt upgrade # 升级已安装的包(不删除) $ apt full-upgrade # 升级(可删除包以解决依赖) $ apt-get dist-upgrade # 等同 full-upgrade 在脚本中建议使用 apt-get/apt-cache,因为其输出格式稳定;交互操作使用 apt 更友好。...

April 26, 2024 · 15 分钟 · 3112 字 · 徐保金

磁盘 I/O 性能诊断与优化

前言 磁盘 I/O 往往是系统性能链条中最慢的一环。一次机械磁盘寻道约 10ms,而内存访问仅约 100ns——两者相差 10 万倍。当业务出现延迟抖动、响应变慢,排查方向总会指向 I/O 子系统。从指标体系出发,结合工具实战与生产案例,建立一套可复用的 I/O 诊断方法论。 I/O 性能指标体系 在动手之前,必须搞清楚四个核心指标的含义及其相互关系。 指标 单位 含义 典型参考值 IOPS 次/秒 每秒完成的 I/O 读写次数 HDD ~100,SATA SSD ~10 万,NVMe SSD ~50 万+ 吞吐量 MB/s 每秒传输的数据量 HDD ~150 MB/s,SATA SSD ~550 MB/s,NVMe SSD ~3000 MB/s+ 延迟 ms/μs 单次 I/O 从提交到完成的耗时 HDD 5-15ms,SSD 0.1-1ms,NVMe 0.02-0.1ms 队列深度 个 等待处理的 I/O 请求数 建议值 NVMe 32-256,SSD 8-32 这四个指标之间存在关键约束关系: 小块随机读写场景下,瓶颈是 IOPS(如数据库 OLTP 4KB 随机写) 大块顺序读写场景下,瓶颈是吞吐量(如日志追加、视频流媒体) 延迟是最终用户感知的指标,即使 IOPS 和吞吐量充足,单次延迟过高仍会导致卡顿 队列深度提升能增加并发,但也意味着单请求等待时间变长 一个重要认知:IOPS × 块大小 ≈ 吞吐量。例如 4KB 块、100 IOPS,吞吐量约 0....

March 27, 2024 · 4 分钟 · 841 字 · 徐保金