一、为什么可观测性是第一生产力
在现代运维和性能调优体系中,可观测性(Observability) 是定位生产环境问题的第一道关口。传统监控关注「已知问题」的阈值告警,而可观测性关注「未知问题」的根因追溯。Linux 内核作为操作系统核心,其可观测性工具栈经历了从 strace 到 perf,再到 eBPF 的三次技术跃迁。
本文将从实战出发,覆盖 CPU、内存、IO、网络四大维度的观测工具栈,最终深入 eBPF 内核编程的生产级落地。
二、CPU 观测:从采样到火焰图
2.1 perf — 内核自带的全能采样器
perf 是 Linux 内核内置的性能分析工具,基于硬件性能计数器(PMC),几乎零开销。
# CPU 级采样,生成调用图
perf record -g -F 99 -p $(pidof java) -- sleep 30
perf report --stdio
# 查看热路径(Hot Path)
perf top -p $(pidof mysqld)
# 统计系统调用
perf trace -p 12345
# 火焰图生成
perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > cpu.svg
2.2 turbostat — 睿频与 C-State 分析
# 每 2 秒采样所有核心
turbostat --interval 2 --show Core,CPU,Avg_MHz,Busy%,Bzy_MHz,TSC_MHz,CoreTmp,PkgWatt
当发现 Avg_MHz 低于标称频率且 Busy% 较高时,需排查散热策略或电源管理限制。
2.3 bpftop — 实时 eBPF 程序观测
bpftop # 类似 top,显示运行中的 eBPF 程序及其 CPU 占用
三、内存观测:四层分析模型
3.1 用户态内存:valgrind massif + smaps
smem -r -k -P java # 按进程排序查看 RSS/USS/PSS
cat /proc//smaps | grep -E '^(Private|Swap|Rss)' # 进程级内存映射
3.2 内核 Slab 分配器:slabtop + /proc/slabinfo
slabtop -s c -o | head -30 # 查看 slab 缓存占用
# dentry 缓存膨胀诊断(常见 OOM 陷阱)
grep dentry /proc/slabinfo
# 清理 slab(仅测试环境)
echo 3 > /proc/sys/vm/drop_caches
3.3 NUMA 拓扑感知:numastat + numactl
numastat -cm # 各 NUMA 节点内存使用
numactl --hardware # 查看 NUMA 拓扑
numastat -p $(pidof java) # 进程级 NUMA 命中率
交叉访问(numa_miss 偏高)会导致内存延迟剧增,需通过 numactl --cpunodebind 绑核。
3.4 vmstat — 内存压力一站式视图
vmstat 1 10
# 关键列:si(swap in)、so(swap out)、free、buff、cache、si/so 非零即告警
四、存储 IO 观测:全栈追踪链路
4.1 iostat + iotop 快速定位
iostat -xz 1 # -x 扩展统计,-z 跳过空设备
# 关键指标:%util、await、avgqu-sz、r/s+w/s
iotop -oPa # 只显示有 IO 的进程,累计总量
4.2 blktrace + blkparse — 块设备层深度追踪
# 追踪读操作(耗时超过 50ms)
blktrace -d /dev/nvme0n1 -w 10 &
sleep 10 && kill %1
blkparse -i nvme0n1.blt -f "%D %2c %8s %5T.%9t %2p %S %n\n" | awk '$6==\"R\" && $4>50 {print}'
4.3 biolatency (BCC) — IO 延迟直方图
/usr/share/bcc/tools/biolatency 5 3 # 5 秒间隔,共 3 次
# 输出 2 次幂直方图,可发现长尾 IO
五、网络观测:从套接字到数据包
5.1 ss — netstat 的现代替代
ss -tlnp | grep LISTEN # TCP 监听端口
ss -tn state established '( dport = :443 )' | wc -L # 活跃 HTTPS 连接数
ss -ti # TCP CPI(cwnd/rtt)
ss -mop # socket 内存使用
5.2 nethogs + iftop — 带宽溯源
nethogs eth0 -t # 按进程统计带宽
iftop -i eth0 -P # 实时连接级流量
5.3 tcpdump — 经典抓包
# 抓取慢查询(RTT > 100ms)特征报文
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'
# 抓取 8080 端口 HTTP 500 响应(粗略过滤)
tcpdump -i eth0 -A 'tcp port 8080 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450'
5.4 tcplife (BCC) — 连接生命周期
/usr/share/bcc/tools/tcplife -T # PID/TID/寿命/字节数/事件
# 可用于识别短连接风暴
六、eBPF 革命:内核级可编程观测
6.1 eBPF 架构概览
eBPF 通过 BPF_PROG_LOAD 系统调用将用户态编译的字节码加载到内核,经过验证器(Verifier)安全检查后挂载到 Tracepoint/Kprobe/Tracepoint/USDT 等钩子点,通过 Ring Buffer/Perf Event 向用户态输出事件流。
用户态 内核空间
┌──────────┐ ┌───────────────┐
│ 编写 C │ verify │ Tracepoint │ → Ring Buffer → BPF Maps
│ 编译 LLVM ├────────→┤ Kprobe │
│ 加载 prog │ │ XDP/skb hooks │
│ 读取 maps │←─────────┘
└──────────┘ perf_event_read
6.2 bpftrace — 单行脚本利器
# 追踪 accept() 调用分布
bpftrace -e 'tracepoint:syscalls:sys_enter_accept { @[comm] = count(); }'
# 统计 read() 延迟直方图(纳秒级)
bpftrace -e 'tracepoint:syscalls:sys_enter_read { @start[tid] = nsecs; }
tracepoint:syscalls:sys_exit_read /@start[tid]/ { @us = hist((nsecs-@start[tid])/1000); }'
# 追踪所有文件打开
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
# 调度器延迟
bpftrace -e 'tracepoint:sched:sched_switch { @[kstack, comm] = count(); }'
6.3 BCC (BPF Compiler Collection) — Python/Lua 接口
# 运行内置工具
/usr/share/bcc/tools/offcputime -K -p $(pidof java) 5 # 内核态 off-CPU
/usr/share/bcc/tools/biosnoop # 逐 IO 追踪
/usr/share/bcc/tools/tcpconnect # 新 TCP 连接追踪
/usr/share/bcc/tools/mdflush # 块层 flush 追踪
/usr/share/bcc/tools/syscount -P 'do_nanosleep' # 系统调用统计
6.4 libbpf + CO-RE — 生产级 eBPF 开发
CO-RE(Compile Once - Run Everywhere) 解决了传统 eBPF 需要目标机器编译的痛点。通过 BTF(BPF Type Format)和重定位信息,编译后的 eBPF 字节码可跨内核版本运行。
// 最小 eBPF 程序:追踪 execve 调用
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
struct event {
u32 pid;
char comm[16];
char filename[256];
};
SEC("tp/syscalls/sys_enter_execve")
int trace_execve(struct trace_event_raw_sys_enter *ctx) {
struct event *e;
e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_probe_read_user_str(&e->filename, sizeof(e->filename), (void *)ctx->args[0]);
bpf_ringbuf_submit(e, 0);
return 0;
}
char _license[] SEC("license") = "GPL";
七、生产级可观测性架构
7.1 Grafana + Prometheus + node_exporter
node_exporter 提供基础主机指标(CPU/内存/IO/网络),配合 Prometheus 的 PromQL 实现告警。但对于内核深度追踪(锁竞争、调度延迟、内存碎片),仍需 eBPF 方案补充。
7.2 Pixie / Hubble — Kubernetes 可观测性
Pixie 内置 eBPF 数据采集,自动抓取 HTTP/gRPC/DNS/Kafka/RabbitMQ 等协议流量,无需修改应用代码。Cilium/Hubble 则提供 L3-L7 网络可观测性和安全策略。
7.3 Katetrina / Parca — 持续性能分析
Parca 以 10s 采样+存储 的方式实现持续性能分析(Continuous Profiling),对比火焰图可发现低 CPU 使用率下的隐性热点。
八、生产环境实战案例
Case 1: 容器 CPU Throttling 定位
现象:容器化应用响应时间突增,top 显示 CPU 使用率不足 30%。
诊断:
kretprobe:pstat + cpu_throttled_time (BCC)
# 发现 latency = cpu_throttled_time / period_quota
# 解决:调整 cgroup cpu.cfs_quota_us
Case 2: 内存泄漏精确定位
现象:RSS 持续增长,free 不减少,重启后缓解。
诊断:
/usr/share/bcc/tools/memleak -p $(pidof java) -o 60000
# 输出分配调用栈和增长速率
# 最终定位到第三方库未释放 SSL session
Case 3: 网络抖动根因
现象:跨 AZ RTT 周期性跳变 5ms→50ms。
诊断:
/usr/share/bcc/tools/tcplife -L 0
# 锁定到 conntrack 表满触发 RTF_DROP
# 解决:调整 net.nf_conntrack_max + 使用 NOTRACK 规则
九、工具选型速查表
| 场景 | 推荐工具 | 原理 |
|---|---|---|
| CPU 热点 | perf + flamegraph | PMU 中断采样 |
| 内存泄漏 | memleak (BCC) | kprobe kmalloc/kfree |
| IO 延迟 | biolatency (BCC) | block_rq_issue/completion |
| 网络抖动 | tcplife (BCC) | kprobe tcp_set_state |
| 系统调用 | strace / bpftrace | ptrace / tracepoint |
| 持续分析 | Parca / Pyroscope | eBPF profiler |
十、总结与展望
Linux 可观测性工具栈已经进入 eBPF-first 时代。相比用户态工具,eBPF 具备三大优势:(1) 内核态执行,零上下文切换开销;(2) 可编程性,按需定制观测逻辑;(3) 安全验证,Verifier 保证不崩溃内核。
随着 eBPF 在容器网络(Cilium)、安全(Tetragon)、可观测性(Pixie)等场景的规模化落地,未来运维将从「被动告警」全面转向「主动可观测」,内核不再是黑盒,而是可编程的透明基础设施。

发表评论 取消回复