I/Oを疑っても iostat はビジーでなく、strace をかければプロセスが重くなる——そんな状況で使えるのが bpftrace です。
bpftraceはeBPFを使ってカーネル内部のイベントをリアルタイムに計測できるトレーシングツールで、本番サーバーへの影響を最小限に抑えながら原因を特定できます。
この記事では、RHEL9系/Ubuntu 24.04 LTSを想定環境として、bpftraceのインストールから実践的なワンライナーによるI/O遅延・システムコール遅延・ネットワーク接続のトレース手順を解説します。
この記事のポイント
・bpftraceはeBPFを使いカーネル内イベントを低オーバーヘッドで計測できるトレーシングツール
・RHEL9/AlmaLinux9・Ubuntu 24.04ともにdnf/aptの1コマンドでインストール可
・I/O遅延・遅いシステムコール・TCP接続のトレースをワンライナーで書ける
・動かない場合の確認ポイントはBTF有無・カーネルバージョン・SELinuxの3点
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
bpftraceとは|eBPFで実現するカーネル内リアルタイムトレーシング
bpftraceは、Linux 4.9以降に搭載されたeBPF(extended Berkeley Packet Filter)を基盤として動作するトレーシングツールです。eBPFはカーネルのソースコードを変更せずに、カーネル内の特定イベントに小さなプログラムを安全にアタッチする仕組みです。bpftraceはこのeBPFをバックエンドとして、
awkに近いシンプルなスクリプト言語でカーネルイベントを計測・集計できます。従来ツールとの比較
従来の
strace はデバッグ対象プロセスの全システムコールにインターセプトするため、CPUオーバーヘッドが20~50%に達することがあります。一方、bpftraceのeBPFプログラムはカーネル内で直接実行されるためコンテキストスイッチが発生せず、本番環境でも動作させられます。perf stat や iostat と組み合わせると相補的です。perf/iostatは「何かがおかしい」という全体像を見せてくれます。bpftraceは「そのおかしさがどのプロセス・どの関数で起きているか」をドリルダウンするのに使います。bpftraceが効果的な場面:
・I/O遅延の特定:どのプロセス・どのデバイスで待ちが発生しているかをマイクロ秒単位で可視化
・システムコール解析:遅いread/writeがどのファイルに対して行われているかを追跡
・ネットワーク観察:TCP接続の確立・TCPリセット・パケットレベルのトレース
・アプリケーションのホットパス特定:uprobeを使い特定関数の呼び出し頻度や処理時間を計測
SystemTap と比べると構文が直感的で、カーネルモジュールのビルドも不要です。ワンライナーから始められるのがbpftraceの強みです。bpftraceのインストール方法|RHEL9・Ubuntu 24.04対応
1. RHEL9系(AlmaLinux9 / Rocky Linux 9)へのインストール
RHEL9系はデフォルトリポジトリにbpftraceが含まれています。# bpftraceをインストール dnf install bpftrace
bpftrace --version
bpftrace v0.20.4
ls /sys/kernel/btf/vmlinux
/sys/kernel/btf/vmlinux が存在すればBTF有効です。RHEL9 / AlmaLinux9はデフォルトでBTFが有効です。2. Ubuntu 24.04 LTS へのインストール
# bpftraceをインストール apt install bpftrace
3. カーネルバージョンの確認
bpftraceの主要機能はLinux 4.9以上で利用できます。全機能(ループ・全プローブタイプ)を使うにはLinux 5.8以上が推奨です。uname -r
bpftraceの基本構文|プローブ・フィルタ・アクション
bpftraceスクリプトの構造は次のとおりです。プローブ名[:フィルタ条件] { アクション }主なプローブの種類:
・tracepoint:カーネル内の静的トレースポイント。引数は
args->フィールド名 でアクセスできる。最も安定して使いやすい・kprobe:カーネル関数の入口に動的に設置するプローブ
・kretprobe:カーネル関数の戻り値を捕捉するプローブ
・uprobe / uretprobe:ユーザー空間アプリケーションの関数を追跡
・interval:s:N:N秒ごとに実行するタイマープローブ(集計結果の定期出力に使う)
よく使う組み込み変数:
・comm:プロセス名(最大16文字)
・pid:プロセスID
・tid:スレッドID
・args:tracepointの引数構造体
・nsecs:単調増加のタイムスタンプ(ナノ秒)
よく使う集計アクション:
・count():イベント数をカウント
・sum(N):値を加算集計
・hist(N):対数ヒストグラムで分布を表示
・printf("..."):書式付き出力
・delete(@map[key]):マップエントリを削除
まず動作確認として、プロセス別のシステムコール回数を3秒ごとに集計するワンライナーを実行します。
bpftrace -e ' tracepoint:raw_syscalls:sys_enter { @calls[comm] = count(); } interval:s:3 { print(@calls); clear(@calls); }'
@calls[mysqld]: 248 @calls[systemd-journal]: 56 @calls[sshd]: 24 @calls[chronyd]: 12
mysqld のシステムコール回数が突出して多い場合、高いI/Oアクティビティかクエリがループ処理を繰り返しているかが疑われます。Ctrl+Cで終了します。
I/O遅延を調べる実践ワンライナー
1. ブロックI/Oのレイテンシ分布を確認する
ディスクI/Oがボトルネックかどうかを確認するには、ブロックI/Oのコンプリートイベントのレイテンシをヒストグラムとして集計します。bpftrace -e ' tracepoint:block:block_rq_issue { @start[args->sector] = nsecs; } tracepoint:block:block_rq_complete /@start[args->sector]/ { @lat_us = hist((nsecs - @start[args->sector]) / 1000); delete(@start[args->sector]); } interval:s:5 { print(@lat_us); clear(@lat_us); }'
@lat_us: [0] 2 | | [1] 318 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| [2, 4) 184 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ | [4, 8) 42 |@@@@@@@ | [8, 16) 19 |@@@ | [32, 64) 5 | | [1024, 2048) 1 | |
2. プロセス別のディスク書き込み量を確認する
どのプロセスがディスクI/Oを大量に発生させているかを特定します。bpftrace -e ' tracepoint:block:block_rq_complete { @bytes[comm] = sum(args->nr_sector * 512); } interval:s:3 { print(@bytes); clear(@bytes); }'
@bytes[mysqld]: 4194304 @bytes[rsync]: 1048576 @bytes[logrotate]: 262144
mysqld が突出して書き込んでいる場合、InnoDBバッファプールのフラッシュやバイナリログの設定見直しにつながります。3. 特定プロセスのI/Oだけを絞り込む
PIDを指定して特定プロセスのI/Oレイテンシだけを計測します。# PID=1234 のプロセスのI/Oレイテンシのみを集計 bpftrace -e ' tracepoint:block:block_rq_issue /pid == 1234/ { @start[args->sector] = nsecs; } tracepoint:block:block_rq_complete /@start[args->sector]/ { @lat_us = hist((nsecs - @start[args->sector]) / 1000); delete(@start[args->sector]); }'
/条件/)を使うと、特定PIDやプロセス名に絞った計測が可能です。調査対象のPIDは ps aux | grep プロセス名 で事前に確認します。システムコール遅延を測定するワンライナー
I/Oの原因がディスクにあるのか、NFS等のネットワークファイルシステムにあるのかを切り分けるには、vfs_read のレイテンシを計測します。1. read()のレイテンシ分布を計測する
bpftrace -e ' kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid]/ { @lat_us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); } interval:s:5 { print(@lat_us); clear(@lat_us); }'
Linuxサーバーの性能設計や障害切り分けを体系的に習得したい場合はLinuxサーバー構築セミナーが参考になります。
2. 遅いread()を発行しているプロセスを特定する
# 1ms以上かかったread()のプロセス名とPIDを出力 bpftrace -e ' kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid] && (nsecs - @start[tid]) > 1000000/ { printf("slow read: comm=%s pid=%d latency=%dms\n", comm, pid, (nsecs - @start[tid]) / 1000000); delete(@start[tid]); }'
slow read: comm=mysqld pid=2341 latency=12ms slow read: comm=java pid=8901 latency=5ms
strace -p PID -e trace=read -T でシステムコールのファイルディスクリプタを確認します(strace はオーバーヘッドが大きいため、対象プロセスを絞ってから短時間だけ実行するのがコツです)。3. openat()でアクセス頻度の高いファイルを特定する
bpftrace -e ' tracepoint:syscalls:sys_enter_openat { @files[str(args->filename)] = count(); } interval:s:5 { print(@files); clear(@files); }'
ネットワーク接続をトレースするワンライナー
1. TCP接続の発生をリアルタイムに追跡する
bpftrace -e 'kprobe:tcp_connect { printf("connect: comm=%s pid=%d\n", comm, pid); }'
現在確立しているTCP接続を確認したい場合は Linux ポート確認の全コマンド(ss・lsof・netstat)を参照してください。bpftraceは「これからの接続」、ss/lsofは「今の状態」として使い分けられます。
2. TCPリセット(RST)の発生を記録する
bpftrace -e ' kprobe:tcp_send_active_reset { @rst[comm] = count(); } interval:s:5 { print(@rst); clear(@rst); }'
/proc/sys/net/ipv4/tcp_fin_timeout や keepalive 設定の見直しにつながります。3. プロセス別にTCP接続確立数をカウントする
bpftrace -e ' kprobe:tcp_connect { @connects[comm] = count(); } interval:s:10 { print(@connects); clear(@connects); }'
lsof -p PID -i や ss -tp で接続先を詳細確認します。bpftraceが動かない時のトラブルシュート
1. 「BTF not found」エラーが出る
ERROR: Could not read BTF data: No such file or directory
/sys/kernel/btf/vmlinux が存在しない場合に発生します。対処は2通りあります。・BTFサポート付きのカーネルをインストールする(RHEL9/Ubuntu 24.04 LTSは標準で有効)
・RHEL8系なら
kernel-devel および bpftrace の新しいバージョンをインストールしてBTFファイルを補完する2. カーネルバージョンが古い場合
ERROR: Failed to create BPF program: Operation not permitted
uname -r でバージョンを確認し、サポート対象カーネルへのアップデートを検討します。3. SELinuxがbpftraceをブロックする(RHEL系)
ERROR: Error loading program: Operation not permitted
ausearch -m avc -ts recent | grep bpf
denied { map_create } のようなAVC拒否が見つかる場合は、bpftraceを sudo で実行しているか確認します。また、bpf_priv ケーパビリティが付与されているかも確認します。デバッグ目的で一時的に確認したい場合は sudo setenforce 0 でPermissiveモードに切り替えることも選択肢ですが、本番環境での常時無効化は避けてください。4. tracepointが見つからない
# 利用可能なtracepointをリストアップ bpftrace -l 'tracepoint:block:*' bpftrace -l 'tracepoint:syscalls:sys_enter_*'
CONFIG_TRACEPOINTS)が有効でないと特定のtracepointが存在しないことがあります。上記コマンドで使えるプローブ名を事前に確認してから記述するのが確実です。本記事のまとめ
| 調査したいこと | 使うプローブ / コマンド |
|---|---|
| ブロックI/Oのレイテンシ分布 | tracepoint:block:block_rq_issue/complete + hist() |
| 書き込みが多いプロセスを特定 | tracepoint:block:block_rq_complete + sum(nr_sector) |
| 遅いread()を発行するプロセスを特定 | kretprobe:vfs_read + 閾値フィルタ |
| 頻繁にopenされるファイルを把握 | tracepoint:syscalls:sys_enter_openat + count() |
| TCP接続をリアルタイム追跡 | kprobe:tcp_connect + printf() |
| TCPリセットの発生を監視 | kprobe:tcp_send_active_reset + count() |
| インストール(RHEL9系) | dnf install bpftrace |
| インストール(Ubuntu 24.04) | apt install bpftrace |
| 動かない場合の確認ポイント | BTFの有無・カーネルバージョン・SELinux AVC |
bpftraceを含む障害切り分けの設計思想やRHEL10対応の実践的なLinuxスキルをLinux Master Pro Seminarで学べます。20年以上・3,100名以上の指導実績をもつ少人数ハンズオンセミナーです。
>> セミナー詳細・日程はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Linuxのvm.swappinessを設定してスワップを制御する方法|メモリ実態の確認からサーバー種別ごとの推奨値まで
- この記事の属するカテゴリ:Linuxトラブルシューティングへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます