bpftraceコマンドの使い方|LinuxのI/O遅延・システムコールをワンライナーで解析する実践手順

運営:リナックスマスター.JP(代表 宮崎智広)
HOME > Linux技術 リナックスマスター.JP(Linuxマスター.JP) > Linuxトラブルシューティング > bpftraceコマンドの使い方|LinuxのI/O遅延・システムコールをワンライナーで解析する実践手順
「このサーバー、CPU使用率はそんなに高くないのにレスポンスが遅い……」

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点


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
姓・名・メールの3つだけ/30秒/解除は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

次に、BTF(BPF Type Format)のサポート状況を確認します。BTFはカーネルのデータ構造情報をカーネル自身が持つ仕組みで、bpftraceのCO-RE(Compile Once, Run Everywhere)機能に必要です。

ls /sys/kernel/btf/vmlinux

/sys/kernel/btf/vmlinux が存在すればBTF有効です。RHEL9 / AlmaLinux9はデフォルトでBTFが有効です。

2. Ubuntu 24.04 LTS へのインストール

# bpftraceをインストール apt install bpftrace

Ubuntu 24.04はLinux 6.8を搭載しており、BTFとbpftraceの動作に必要な機能が標準で有効です。

3. カーネルバージョンの確認

bpftraceの主要機能はLinux 4.9以上で利用できます。全機能(ループ・全プローブタイプ)を使うにはLinux 5.8以上が推奨です。

uname -r

RHEL9・Ubuntu 24.04はいずれも要件を満たしています。

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 | |

1,000μs(1ms)以上の山が多い場合はディスクが遅延の主因です。SSDであれば通常100μs未満、HDDなら1~10ms程度が参考値です(実際の性能は環境により大きく異なります)。

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]); }'

bpftraceのフィルタ条件(/条件/)を使うと、特定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); }'

数百μs以上のlatencyが多発している場合、ネットワークファイルシステム(NFSなど)や低速ストレージへのアクセスが疑われます。ローカルSSDであればほとんどが10μs未満に収まるのが目安です。

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); }'

特定のログファイルや設定ファイルが頻繁にopenされている場合、アプリケーションのファイルディスクリプタのキャッシュ不足や、ループ内での不必要なopen/closeが起きている可能性があります。

ネットワーク接続をトレースするワンライナー

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); }'

TCPリセットが頻発している場合、接続タイムアウトや半開放状態(half-open)のコネクションが積み上がっていることがあります。/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

Linux 4.9未満では多くのプローブタイプが使えません。uname -r でバージョンを確認し、サポート対象カーネルへのアップデートを検討します。

3. SELinuxがbpftraceをブロックする(RHEL系)

ERROR: Error loading program: Operation not permitted

RHEL9のSELinuxがBPFシステムコールを拒否している場合があります。まずauditログを確認します。

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は「なんとなく重い」の原因を、再起動やエージェント追加なしに特定できる強力なツールです。ワンライナーからスタートして、徐々にスクリプトに育てることで、障害対応の引き出しが大きく広がります。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、
bpftraceを含む障害切り分けの設計思想やRHEL10対応の実践的なLinuxスキルをLinux Master Pro Seminarで学べます。20年以上・3,100名以上の指導実績をもつ少人数ハンズオンセミナーです。
>> セミナー詳細・日程はこちら

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録

運営

リナックスマスター.JP(代表 宮崎智広)

株式会社イーネットマーキュリーが運営するLinux教育サイトです。代表の宮崎智広は現役のLinuxサーバー管理者として20年以上の実務経験を持ち、累計3,100名以上のエンジニアを指導してきました。実践型のLinuxセミナーや無料マニュアルの配布を通じてLinux人材の育成に取り組んでいます。