一、大白话:为啥要一整套"工具链"
                                                                                                                          内核是个黑盒,你不能 var_dump($kernel)。但生产上又天天碰到:
                                                                                                                          - 服务慢了,CPU 没占满,到底卡在哪?
  - 丢包了,是网卡丢、协议栈丢、还是应用没读?
  - 某个进程偶尔 OOM,谁在吃内存?
  - 系统调用某一秒堆积,是哪个进程?

  这些问题没有单一答案——你需要一整套工具,各管一块,组合起来才看得清全貌。这就是"调试与可观测性工具链"。

  它们背后的技术原理其实只有几种:

  ┌───────────────────────────────────────────────────────────┐
  │  底层机制:                                                 │
  │  ① tracepoint/kprobe/fentry/uprobe  ← 埋点抓事件            │
  │  ② perf_event / PMU                 ← 硬件采样/计数          │
  │  ③ ftrace                           ← 函数级轨迹            │
  │  ④ BPF                              ← 在内核里跑你的小程序    │
  │  ⑤ /proc、/sys                      ← 拉取当前状态          │
  │  ⑥ debugfs / tracefs                ← 低级调试文件系统       │
  └───────────────────────────────────────────────────────────┘
           │           │           │           │
           ▼           ▼           ▼           ▼
      ┌─────────┐┌─────────┐┌─────────┐┌─────────┐
      │  perf   ││  bpftrace││   bcc  ││   ftrace │
      │  strace ││  bpftool ││  sysdig ││   drgn   │
      │   top   ││  retsnoop││  crash ││   lldb   │
      └─────────┘└─────────┘└─────────┘└─────────┘

  每个工具本质上都是在把这 6 种机制包装成人能用的界面。你理解了机制,就能在任何 Linux 上组合出自己要的观测视图。

  ---
  二、工具矩阵:按"你要解决什么问题"分类

  这张表记住,比记一百个命令有用:

  🧭  资源 & 状态快照(无需开发)

  ┌─────────────────────────────────┬─────────────────────────────┬───────────────────────────────┐
  │              工具               │           问题域            │             机制              │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ top / htop / atop               │ CPU、内存宏观               │ /proc                         │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ vmstat, iostat, mpstat, pidstat │ 分维度统计                  │ /proc                         │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ ss                              │ socket 状态(替代 netstat) │ netlink                       │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ free, slabtop                   │ 内存 & slab                 │ /proc/meminfo, /proc/slabinfo │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ lsof, fuser                     │ 文件/fd 占用                │ /proc                         │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ dmesg                           │ 内核日志                    │ /dev/kmsg                     │
  ├─────────────────────────────────┼─────────────────────────────┼───────────────────────────────┤
  │ sar                             │ 历史统计                    │ sysstat 后台采样              │
  └─────────────────────────────────┴─────────────────────────────┴───────────────────────────────┘

  🔬 调用级追踪

  ┌────────┬─────────────────┬──────────────────────────────┐
  │  工具  │     抓什么      │             开销             │
  ├────────┼─────────────────┼──────────────────────────────┤
  │ strace │ 系统调用 + 参数 │ 中(ptrace,慢进程 2-10 倍) │
  ├────────┼─────────────────┼──────────────────────────────┤
  │ ltrace │ 库调用          │ 中                           │
  ├────────┼─────────────────┼──────────────────────────────┤
  │ gdb    │ 断点调试        │ 高(停进程)                 │
  └────────┴─────────────────┴──────────────────────────────┘

  ⚡ 高性能事件与 BPF

  ┌──────────────┬──────────────────────────────────────────────────┐
  │     工具     │                       定位                       │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ perf         │ 采样、PMU、统计、flamegraph 生成                 │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ ftrace       │ 函数级轨迹(/sys/kernel/debug/tracing)          │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ trace-cmd    │ ftrace 的好用包装                                │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ bpftrace     │ 一行命令写 BPF 脚本(awk 风格)                  │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ bcc          │ Python 写 BPF 工具(execsnoop 等 100+ 现成工具) │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ bpftool      │ BPF 官方管理工具(看 prog/map/btf)              │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ retsnoop     │ 函数返回值/错误链追踪                            │
  ├──────────────┼──────────────────────────────────────────────────┤
  │ libbpf-tools │ 编译好的 BPF 工具集,静态二进制                  │
  └──────────────┴──────────────────────────────────────────────────┘

  🧠 深度内核调试

  ┌──────────────┬────────────────────────────────────────────────────┐
  │     工具     │                        场景                        │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ kgdb / kdb   │ 内核源码级调试(需串口/虚拟机)                    │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ drgn         │ 活内核 + coredump 的 Python 交互式探查(现代首选) │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ crash        │ 传统 vmcore 分析                                   │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ kdump        │ 崩溃时自动抓 coredump                              │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ makedumpfile │ 压缩/过滤 vmcore                                   │
  ├──────────────┼────────────────────────────────────────────────────┤
  │ SystemTap    │ 老牌(被 BPF 挤得快没人用了)                      │
  └──────────────┴────────────────────────────────────────────────────┘

  🔥 火焰图与专项

  ┌────────────────────────────────────────────────┬──────────────────────────┐
  │                      工具                      │           用途           │
  ├────────────────────────────────────────────────┼──────────────────────────┤
  │ FlameGraph (Brendan Gregg)                     │ perf script → svg 火焰图 │
  ├────────────────────────────────────────────────┼──────────────────────────┤
  │ hotspot                                        │ GUI perf 分析器          │
  ├────────────────────────────────────────────────┼──────────────────────────┤
  │ BCC/tools 里的 offcputime, wakeuptime, runqlat │ 专项诊断                 │
  └────────────────────────────────────────────────┴──────────────────────────┘

  ---
  三、选工具的决策流程(面试常问)

  症状?
  │
  ├─ "CPU 跑高了,哪个函数?"
  │   └─→ perf record -F 99 -a -g → perf report / FlameGraph
  │
  ├─ "CPU 没高,但服务慢"
  │   └─→ offcputime-bpfcc(看阻塞在哪)/ runqlat(调度延迟)
  │
  ├─ "某个进程在调什么系统调用?"
  │   └─→ strace -p PID -c(统计)或 syscount-bpfcc
  │
  ├─ "某类事件想长期统计"
  │   └─→ bpftrace / bcc 写脚本,tracepoint 抓
  │
  ├─ "内核偶尔崩,要抓现场"
  │   └─→ kdump 配好 + crash/drgn 分析 vmcore
  │
  ├─ "想看一个结构体字段的运行时值"
  │   └─→ drgn(活内核,Python 交互)或 gdb vmlinux
  │
  ├─ "丢包追踪"
  │   └─→ dropwatch / skb-drop tracepoint / tcplife-bpfcc
  │
  ├─ "文件 IO 慢"
  │   └─→ biolatency / biotop / bpftrace io 脚本
  │
  └─ "TCP 连接异常"
      └─→ tcpconnect / tcpretrans / tcplife(BCC tools)

  ---
  四、完整流程:排查一个"CPU 高"问题

  假设你被叫起来,线上 CPU 100%,用户投诉慢。标准套路:

  ① 宏观:看看到底谁在烧
          top / pidstat 1
          → 锁定 PID=1234 的 nginx 吃了 95% CPU

  ② 维度:user 态还是 kernel 态?
          top 看 %us vs %sy
          → %sy 占 70%,说明烧在内核

  ③ 函数级:是哪个内核函数?
          perf top -p 1234
          → 最热的是 inet_csk_accept / spin_lock

  ④ 全貌:生成火焰图
          perf record -F 99 -p 1234 -g -- sleep 30
          perf script | stackcollapse-perf.pl | flamegraph.pl > f.svg
          → 火焰图显示一个大平顶在锁竞争

  ⑤ 验证假设:是不是 accept 锁竞争?
          bpftrace -e 'kprobe:__inet_lookup_listener { @[comm] = count(); }'
          → 确认就是这个路径

  ⑥ 写专项工具持续监控
          bpftrace -e '
            profile:hz:99 { @[kstack] = count(); }' -o stacks.txt

  ⑦ 根因找到 → 修代码 → 再测一次确认

  这 7 步里用到了 top、pidstat、perf top、perf record、FlameGraph、bpftrace——一个问题要跨工具,而不是死磕一个。

  ---
  五、PHP 完整代码:一个工具链调度器

  这段 PHP 把上面的思路做成交互式诊断助手:你报症状,它告诉你该跑哪个工具链,并模拟它们的输出。存成
  debug_toolchain.php,php debug_toolchain.php 跑。

  <?php
  /**
   * Linux 调试工具链模拟器
   * 模拟 perf/bpftrace/strace/ftrace/drgn 等工具如何协同工作
   */

  // ══ 1. 底层机制抽象 ══════════════════════════════════════
  abstract class Mechanism {
      abstract public function name(): string;
      abstract public function cost(): string;   // 开销估算
  }
  class Tracepoint extends Mechanism {
      public function name(): string { return 'tracepoint'; }
      public function cost(): string { return '极低 (~20ns/事件)'; }
  }
  class Kprobe extends Mechanism {
      public function name(): string { return 'kprobe'; }
      public function cost(): string { return '低 (~1μs/事件)'; }
  }
  class Fentry extends Mechanism {
      public function name(): string { return 'fentry'; }
      public function cost(): string { return '极低 (~100ns/事件)'; }
  }
  class Uprobe extends Mechanism {
      public function name(): string { return 'uprobe'; }
      public function cost(): string { return '中 (~2μs/事件)'; }
  }
  class PerfEvent extends Mechanism {
      public function name(): string { return 'perf_event'; }
      public function cost(): string { return '由采样率决定'; }
  }
  class Ptrace extends Mechanism {
      public function name(): string { return 'ptrace'; }
      public function cost(): string { return '高 (进程 2-10× 变慢)'; }
  }
  class ProcFS extends Mechanism {
      public function name(): string { return '/proc 读'; }
      public function cost(): string { return '零(状态快照)'; }
  }

  // ══ 2. 工具抽象:每个工具基于一种或多种机制 ═══════════════
  abstract class Tool {
      public function __construct(
          public string $name,
          public array  $mechanisms,   // 依赖的底层机制
          public array  $strengths,    // 擅长什么
          public string $overhead      // 低/中/高
      ) {}
      abstract public function describe(): string;
      abstract public function sampleOutput(string $scenario): string;
  }

  class PerfTool extends Tool {
      public function __construct() {
          parent::__construct(
              'perf', [new PerfEvent(), new Tracepoint(), new Kprobe()],
              ['CPU 采样', 'PMU 硬件计数', '函数级火焰图'], '低-中'
          );
      }
      public function describe(): string {
          return "采样式 profile,默认 99Hz 就够。perf record / report / top / stat 都在一个工具里。";
      }
      public function sampleOutput(string $scenario): string {
          return match ($scenario) {
              'cpu_hot' => <<<OUT
  # perf top -p 1234
    45.12%  [kernel]  __inet_lookup_listener
    18.77%  [kernel]  _raw_spin_lock_bh
     9.33%  nginx     ngx_event_process_posted
     5.21%  [kernel]  tcp_v4_rcv
  OUT,
              default => "(perf 无对应输出)",
          };
      }
  }

  class BpftraceTool extends Tool {
      public function __construct() {
          parent::__construct(
              'bpftrace', [new Tracepoint(), new Kprobe(), new Fentry(), new Uprobe()],
              ['一行脚本', '聚合', '直方图', '实时监控'], '低'
          );
      }
      public function describe(): string {
          return "awk 风格 DSL,内联写 BPF。最好用的事件统计工具。";
      }
      public function sampleOutput(string $scenario): string {
          return match ($scenario) {
              'syscall_count' => <<<OUT
  # bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[probe] = count(); }'
  @[sys_enter_epoll_wait]:  58234
  @[sys_enter_read]:        31100
  @[sys_enter_write]:       28012
  @[sys_enter_futex]:        9823
  OUT,
              'io_hist' => <<<OUT
  # bpftrace -e 'tracepoint:block:block_rq_issue { @ = hist(args->bytes); }'
  @:
  [4K, 8K)      1024 |@@@@@@@@@@@@@@@@@@@@                       |
  [8K, 16K)      410 |@@@@@@@@                                   |
  [64K,128K)     199 |@@@@                                       |
  [1M, 2M)        38 |                                           |
  OUT,
              default => "(bpftrace 无对应输出)",
          };
      }
  }

  class BccTool extends Tool {
      public function __construct() {
          parent::__construct(
              'bcc', [new Tracepoint(), new Kprobe(), new Fentry()],
              ['100+ 现成工具', '复杂逻辑用 Python 写', '生产级'], '低'
          );
      }
      public function describe(): string {
          return "execsnoop/opensnoop/biolatency/offcputime... 闭眼用。";
      }
      public function sampleOutput(string $s): string {
          return match ($s) {
              'offcpu' => <<<OUT
  # offcputime-bpfcc -p 1234 5
      finish_task_switch
      __schedule
      schedule
      futex_wait_queue_me
      -    nginx (1234)
          12043214
  OUT,
              'exec' => <<<OUT
  # execsnoop-bpfcc
  PID    PPID   RET ARGS
  5821   4120     0 /bin/bash -c echo hi
  5822   5821     0 /usr/bin/python3 worker.py
  OUT,
              default => '',
          };
      }
  }

  class StraceTool extends Tool {
      public function __construct() {
          parent::__construct(
              'strace', [new Ptrace()],
              ['单进程 syscall', '参数详细', '调试现场'], '高'
          );
      }
      public function describe(): string {
          return "ptrace 原理,拖慢被跟踪进程。只用于临时排障,不做长期监控。";
      }
      public function sampleOutput(string $s): string {
          return match ($s) {
              'syscall_trace' => <<<OUT
  # strace -p 1234 -c -- sleep 10
  % time     seconds  usecs/call     calls    syscall
   62.14     1.200431          21     57100    epoll_wait
   18.22     0.352014          11     31223    read
    9.10     0.175820           6     28012    write
  OUT,
              default => '',
          };
      }
  }

  class FtraceTool extends Tool {
      public function __construct() {
          parent::__construct(
              'ftrace', [new Tracepoint(), new Kprobe()],
              ['函数调用图', 'irq/sched 轨迹', '无需编译'], '低'
          );
      }
      public function describe(): string {
          return "通过 /sys/kernel/debug/tracing 读写开关。trace-cmd 是它的糖。";
      }
      public function sampleOutput(string $s): string {
          return match ($s) {
              'funcgraph' => <<<OUT
  # trace-cmd record -p function_graph -g vfs_read -- cat /etc/hosts
   vfs_read() {
     rw_verify_area() { ... 0.2us }
     __vfs_read() {
       generic_file_read_iter() { ... 5.4us }
     } 6.1us
   } 6.8us
  OUT,
              default => '',
          };
      }
  }

  class DrgnTool extends Tool {
      public function __construct() {
          parent::__construct(
              'drgn', [new ProcFS()],
              ['活内核探查', 'Python 交互', '跨 coredump'], '零'
          );
      }
      public function describe(): string {
          return "跟 gdb 不同:不改内核状态,只读。看结构体字段、遍历链表、算统计。";
      }
      public function sampleOutput(string $s): string {
          return match ($s) {
              'inspect_task' => <<<OUT
  >>> from drgn.helpers.linux import find_task
  >>> t = find_task(prog, 1234)
  >>> t.comm.string_().decode()
  'nginx'
  >>> t.mm.total_vm * 4096 / 1024 / 1024
  128.5
  OUT,
              default => '',
          };
      }
  }

  class ProcTools extends Tool {
      public function __construct() {
          parent::__construct(
              'top/pidstat/vmstat/ss',
              [new ProcFS()],
              ['零开销', '宏观快照', '哪里都有'], '零'
          );
      }
      public function describe(): string {
          return "/proc 拉取即时状态。所有诊断的起点。";
      }
      public function sampleOutput(string $s): string {
          return match ($s) {
              'top' => <<<OUT
    PID USER    PR  NI   VIRT   RES  S  %CPU  %MEM  COMMAND
   1234 www     20   0 2.1g   512m  R  95.3   6.4  nginx
   4567 mysql   20   0 8.3g   6.0g  S  12.1  75.0  mysqld
  OUT,
              default => '',
          };
      }
  }

  // ══ 3. 诊断引擎:症状 → 推荐工具链 ═══════════════════════
  class Diagnostician {
      /** @var Tool[] */ public array $tools;

      public function __construct() {
          $this->tools = [
              'proc'     => new ProcTools(),
              'perf'     => new PerfTool(),
              'bpftrace' => new BpftraceTool(),
              'bcc'      => new BccTool(),
              'strace'   => new StraceTool(),
              'ftrace'   => new FtraceTool(),
              'drgn'     => new DrgnTool(),
          ];
      }

      public function diagnose(string $symptom): array {
          $plans = [
              'cpu_high' => [
                  ['宏观:哪个进程在烧',          'proc',     'top'],
                  ['函数级采样',                  'perf',     'cpu_hot'],
                  ['生成火焰图',                  'perf',     'cpu_hot'],
                  ['验证锁竞争假设',              'bpftrace', 'syscall_count'],
              ],
              'cpu_low_but_slow' => [
                  ['宏观看状态',                  'proc',     'top'],
                  ['看进程阻塞在哪(off-CPU)',   'bcc',      'offcpu'],
                  ['调度延迟分布',                'bpftrace', 'io_hist'],
              ],
              'who_opens_what' => [
                  ['实时看 exec',                 'bcc',      'exec'],
                  ['全系统 syscall 分布',         'bpftrace', 'syscall_count'],
              ],
              'io_slow' => [
                  ['IO 大小直方图',               'bpftrace', 'io_hist'],
                  ['生产监控用 BCC',              'bcc',      'offcpu'],
                  ['函数级轨迹看内核路径',        'ftrace',   'funcgraph'],
              ],
              'syscall_weirdness' => [
                  ['临时精确抓一个进程',          'strace',   'syscall_trace'],
                  ['长期统计',                    'bpftrace', 'syscall_count'],
              ],
              'kernel_state_peek' => [
                  ['活内核探查结构体',            'drgn',     'inspect_task'],
              ],
          ];
          return $plans[$symptom] ?? [];
      }

      public function run(string $symptom): void {
          echo "\n════════════════════════════════════════════════════════\n";
          echo "症状:$symptom\n";
          echo "════════════════════════════════════════════════════════\n";
          $plan = $this->diagnose($symptom);
          if (!$plan) { echo "未知症状\n"; return; }

          foreach ($plan as $step => [$goal, $toolKey, $scenario]) {
              $tool = $this->tools[$toolKey];
              printf("\n【步骤 %d】%s\n", $step + 1, $goal);
              printf("  → 工具:%s\n", $tool->name);
              printf("  → 底层机制:%s\n",
                  implode(', ', array_map(fn($m) => $m->name(), $tool->mechanisms)));
              printf("  → 开销:%s\n", $tool->overhead);
              $out = $tool->sampleOutput($scenario);
              if ($out) {
                  echo "  → 示例输出:\n";
                  foreach (explode("\n", $out) as $l) echo "      $l\n";
              }
          }
      }
  }

  // ══ 4. 跑一遍 ═══════════════════════════════════════════
  $d = new Diagnostician();
  $d->run('cpu_high');
  $d->run('cpu_low_but_slow');
  $d->run('who_opens_what');
  $d->run('io_slow');
  $d->run('syscall_weirdness');
  $d->run('kernel_state_peek');

  // ══ 5. 打印工具 <-> 机制的矩阵 ═══════════════════════════
  echo "\n════════════════════════════════════════════════════════\n";
  echo " 工具 × 底层机制 矩阵\n";
  echo "════════════════════════════════════════════════════════\n";
  $allMech = ['tracepoint','kprobe','fentry','uprobe','perf_event','ptrace','/proc 读'];
  printf("%-12s", '');
  foreach ($allMech as $m) printf("%-12s", $m);
  echo "\n";
  foreach ($d->tools as $t) {
      printf("%-12s", $t->name);
      $owned = array_map(fn($m) => $m->name(), $t->mechanisms);
      foreach ($allMech as $m) printf("%-12s", in_array($m, $owned) ? '✓' : '·');
      echo "\n";
  }

  输出节选

  ════════════════════════════════════════════════════════
  症状:cpu_high
  ════════════════════════════════════════════════════════

  【步骤 1】宏观:哪个进程在烧
    → 工具:top/pidstat/vmstat/ss
    → 底层机制:/proc 读
    → 开销:零
    → 示例输出:
          PID USER    PR  NI   VIRT   RES  S  %CPU  %MEM  COMMAND
         1234 www     20   0 2.1g   512m  R  95.3   6.4  nginx

  【步骤 2】函数级采样
    → 工具:perf
    → 底层机制:perf_event, tracepoint, kprobe
    → 开销:低-中
    → 示例输出:
          45.12%  [kernel]  __inet_lookup_listener
          18.77%  [kernel]  _raw_spin_lock_bh

  ...

  ════════════════════════════════════════════════════════
   工具 × 底层机制 矩阵
  ════════════════════════════════════════════════════════
              tracepoint  kprobe  fentry  uprobe  perf_event  ptrace  /proc 读
  proc        ·           ·       ·       ·       ·            ·       ✓
  perf        ✓           ✓       ·       ·       ✓            ·       ·
  bpftrace    ✓           ✓       ✓       ✓       ·            ·       ·
  bcc         ✓           ✓       ✓       ·       ·            ·       ·
  strace      ·           ·       ·       ·       ·            ✓       ·
  ftrace      ✓           ✓       ·       ·       ·            ·       ·
  drgn        ·           ·       ·       ·       ·            ·       ✓

  这个矩阵比任何教程都清楚——每个工具只是对底层 6 种机制的不同包装。理解了这一点你就能:
  - 自己不会装的机器上,回退到最基础的 /proc 工具链
  - 遇到性能关键场景,直接选 fentry/tracepoint,避开 ptrace 和 kprobe
  - 工具坏了能找到替代(bcc 没装?同样效果用 bpftrace 一行写)

  ---
  六、最佳方式:实战工具链组合拳

  生产机必装的工具集

  一台线上机最低配置:

  # Debian/Ubuntu
  apt install linux-tools-common linux-tools-$(uname -r) \
              bpfcc-tools bpftrace \
              trace-cmd sysstat \
              strace lsof htop

  # Red Hat/CentOS
  yum install perf bcc-tools bpftrace trace-cmd \
              sysstat strace lsof htop

  现代发行版推荐加:

  # drgn:活内核 Python 探查(做深度调试用)
  pip install drgn

  # libbpf-tools:静态编译的 BCC 等价工具(启动快、不用装 Python)
  # https://github.com/libbpf/libbpf-bootstrap

  典型任务 → 一行命令速查

  # 看哪个进程在吃 CPU(交互)
  top                         # 通用
  htop                        # 彩色版
  pidstat 1                   # 按进程刷新

  # CPU 采样 + 火焰图
  perf record -F 99 -a -g -- sleep 30
  perf script | ~/FlameGraph/stackcollapse-perf.pl | \
                ~/FlameGraph/flamegraph.pl > cpu.svg

  # 看进程阻塞在哪(off-CPU 时间)
  offcputime-bpfcc -p <PID> 30 > off.stacks
  ~/FlameGraph/flamegraph.pl --colors=io off.stacks > off.svg

  # 系统调用排行
  syscount-bpfcc -d 10
  # 或
  bpftrace -e 'tracepoint:syscalls:sys_enter_* {
    @[probe] = count();
  }' -c 'sleep 10'

  # exec 实时审计
  execsnoop-bpfcc

  # 所有打开的文件
  opensnoop-bpfcc

  # 文件 IO 延迟分布
  biolatency-bpfcc 10 1

  # TCP 连接生命周期
  tcplife-bpfcc

  # TCP 重传
  tcpretrans-bpfcc

  # 看内核函数调用关系
  trace-cmd record -p function_graph -g vfs_read
  trace-cmd report | less

  # 活内核看数据结构(drgn)
  drgn
  >>> for t in for_each_task(prog):
  ...     if t.comm.string_() == b'nginx':
  ...         print(t.pid, t.mm.total_vm)

  几个常见误用

  1. strace 上生产 = 悲剧。ptrace 让进程慢 5-10 倍,QPS 立刻掉。生产只用 bpftrace/bcc。
  2. perf record 全系统 + 采样率过高。-F 999 -a 在高负载机上可能自己就占几个百分点 CPU。日常 99Hz 足够。
  3. bpftrace 高频点打印。tracepoint:tcp:tcp_retransmit_skb { printf("...") } 一秒几十万次会把 trace_pipe 写爆。聚合用
  @[...] = count(),不要 print。
  4. 只记得一种工具。CPU 高 → 只会 top;网络问题 → 只会 tcpdump。工具链的价值就是组合,top 给方向,perf 给函数,bpftrace
   给根因。
  5. 不看开销就挂 kprobe。kprobe:__kmalloc 这种极高频点,就算不做事光是触发都会让系统明显变慢。优先找 tracepoint,其次
  fentry,最后才是 kprobe。
  6. 忘记卸载。临时装的探针不取下,等下次登录发现系统"莫名慢了几个百分点"——bpftrace 会话退了没事,用 bpftool prog show
  检查有没有 pin 住的。

  组合拳的 4 种经典套路

  套路 1:CPU 热点定位
  top → perf record → perf script → flamegraph → bpftrace 验证

  套路 2:延迟根因
  pidstat → offcputime → runqlat → bpftrace 定点抓调用栈

  套路 3:网络丢包
  ss → dropwatch → skb:kfree_skb tracepoint → bpftrace 加上 kstack

  套路 4:内存异常
  free/slabtop → /proc/meminfo → drgn 遍历 slab → memleak-bpfcc

  可观测性的四个档次

  Brendan Gregg 提过一个视角,按"知识密度"分:

  ┌────────┬───────────────────────────┬───────────────────┐
  │  档次  │         典型工具          │    能回答什么     │
  ├────────┼───────────────────────────┼───────────────────┤
  │ 计数器 │ top, vmstat, /proc        │ "发生多少次"      │
  ├────────┼───────────────────────────┼───────────────────┤
  │ 跟踪   │ strace, ftrace            │ "每次是啥参数"    │
  ├────────┼───────────────────────────┼───────────────────┤
  │ 剖析   │ perf record               │ "时间都花在哪"    │
  ├────────┼───────────────────────────┼───────────────────┤
  │ 监控   │ Prometheus + bpf_exporter │ "历史趋势 + 告警" │
  └────────┴───────────────────────────┴───────────────────┘

  生产可观测性不是选一档,而是四档都要在。计数器做监控大盘,剖析做慢查询诊断,跟踪做复现,历史监控抓趋势。

  深入阅读入口

  - 《BPF Performance Tools》 (Brendan Gregg) — 这个领域的圣经
  - man perf, man trace-cmd — 比教程更准
  - bcc/tools/ GitHub 目录 — 每个 .py 文件都是一个学习样本
  - brendangregg.com — 火焰图发明人,案例博客全开
  - Linux Plumbers Conf 每年的 BPF/Tracing 分论坛视频

  一句话收尾:Linux 的调试与可观测性不是一个工具,是一条流水线——/proc 看状态、perf 看热点、bpftrace/bcc 写探针、ftrace
  看轨迹、drgn 看内部。它们共享六种底层机制(tracepoint/kprobe/fentry/uprobe/perf_event/ptrace),选对机制比选对工具更重
  要。排障的专业度不体现在会用多少工具,而体现在知道哪个症状配哪几把刀,以及刀怎么组合着上。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐