なぜ本番でbpftraceを使うのか
I/Oレイテンシの問題はアプリケーションのエラーログだけでは原因が特定しにくく、ストレージ・ブロック層・ファイルシステム・カーネルスケジューラのどこにボトルネックがあるかを切り分けるのに時間がかかります。従来はiostat・sar・blktraceといったツールが使われてきましたが、これらは統計値の粗さや採取タイミングの制約から「スパイクが発生している瞬間だけを捉える」のが難しいという弱点があります。
bpftrace(BPF拡張トレーサ)はカーネル内のトレースポイントやkprobeにアタッチし、発生したイベントごとにマイクロ秒単位の計測やスタックトレースの取得をリアルタイムで行えます。カーネルコードを変更せず、モジュールのロードも不要で、スクリプト終了後はアタッチが自動解除されます。この「後片付けが自動」という性質が本番での採用ハードルを下げています。
ただし「後片付けが自動」と「副作用がゼロ」は同義ではありません。適切な理解と手順を踏まずに使うと、高頻度イベントへの誤ったアタッチがCPU負荷を押し上げ、診断が新たな問題を引き起こすこともあります。本記事では安全に使うための前提確認から始め、実際の診断フローと切り戻し方針まで1本で整理します。
カーネルトレースポイントとkprobeの違いを理解する
bpftraceでアタッチできるフックには大きく2種類あります。
トレースポイントはカーネルのソースコード内にあらかじめ埋め込まれた静的なフックです。ABIが安定しており、カーネルバージョンをまたいでも引数の意味が変わりにくいという利点があります。I/O診断では block:block_rq_issue(リクエスト発行)・block:block_rq_complete(リクエスト完了)・block:block_bio_queue(BIOエンキュー)が代表的です。まず利用可能なトレースポイントを確認するには以下を実行します。
bpftrace -l 'tracepoint:block:*'
kprobeはカーネル内の任意の関数エントリ/リターンにアタッチする動的フックです。トレースポイントがない内部関数を掘り下げたいときに使いますが、カーネルバージョンによって関数シグネチャが変わるため本番での長期運用には向きません。診断の初期段階ではトレースポイントを優先し、どうしても必要な場合にのみkprobeを使うという方針が現実的です。
2026年時点でRHEL 9系・Ubuntu 24.04 LTS・Debian 12ではカーネル6.x台が標準となっており、block:block_rq_issue の引数に dev・sector・nr_sector・rwbs(読み書き種別フラグ)が含まれています。フィールド定義は /sys/kernel/debug/tracing/events/block/block_rq_issue/format で確認できます。
本番適用前に確認すべき安全チェック
bpftraceの実行にはroot権限またはCAP_BPF+CAP_SYS_ADMINが必要です。本番サーバで直接rootを使う運用は避け、sudo経由でコマンドを限定するか、専用の診断用権限セットを設計するのが望ましいです。
次に、アタッチ先のイベント頻度を事前に把握します。高スループットのデータベースサーバではブロックI/Oイベントが毎秒数万件発生することもあり、そこにbpftrace scriptをnaiveに書くと内部のBPFマップ処理がCPUを圧迫します。まず perf stat -e block:block_rq_issue -- sleep 5 で5秒間のイベント件数を確認し、毎秒1万件を超える環境では集計粒度を粗くする(例: histogramに落とし、個別ログは出さない)設計にします。
また、bpftrace自体のバージョンも確認してください。0.20以降(2024年後半リリース)ではカーネル6.x向けのトレースポイント互換性が改善されています。
bpftrace --version
古いディストリのリポジトリには0.16系が入っていることがあり、その場合はカーネル6.xのトレースポイント引数が一部取得できません。必要であればGitHubから静的バイナリをダウンロードして /usr/local/bin に置く方法が現実的です(バイナリの検証はSHA-256チェックサムとgpg署名で行ってください)。
I/Oレイテンシ診断のステップバイステップ
以下は、デバイス単位のリクエスト完了レイテンシをヒストグラムで集計するスクリプトの例です。スクリプトは診断対象サーバとは別の安全なディレクトリ(例: /opt/diag/)に保存し、実行します。
#!/usr/bin/env bpftrace
// ファイル: /opt/diag/io_lat.bt
BEGIN
{
printf("Tracing block I/O latency... Hit Ctrl-C to end.\n");
}
tracepoint:block:block_rq_issue
{
@start[args->dev, args->sector] = nsecs;
}
tracepoint:block:block_rq_complete
/@start[args->dev, args->sector]/
{
$lat = (nsecs - @start[args->dev, args->sector]) / 1000;
@latency_us = hist($lat);
delete(@start[args->dev, args->sector]);
}
END
{
clear(@start);
}
実行は以下のとおりです。
sudo bpftrace /opt/diag/io_lat.bt
Ctrl-Cで終了するとヒストグラムが表示されます。見方として、大半のリクエストが1ms未満(1000µs未満)に収まっていれば通常範囲、10ms超のバケットに集中が見られる場合はストレージまたはI/Oスケジューラの問題、100ms超が散発する場合はデバイスファームウェアの不具合・ケーブル劣化・RAIDの再同期などが候補になります。
次に、特定のプロセスに絞り込みたい場合は comm 変数を使います。
tracepoint:block:block_rq_issue
/comm == "postgres"/
{
@start[args->dev, args->sector] = nsecs;
}
このようにフィルタを追加することで取得データ量を絞り、BPFマップの肥大化を防げます。
障害切り分けのワークフロー
実際の障害調査では単一のスクリプトで完結することは少なく、階層ごとに問題を絞り込む手順が有効です。以下は典型的な切り分けの流れです。
- ステップ1: ブロック層全体のレイテンシ確認 — 上記の
io_lat.btを実行し、デバイス全体として遅延が出ているかを把握します。 - ステップ2: 書き込み/読み取りの分離 —
args->rwbsフィールドに “W”(Write)・”R”(Read)・”D”(Discard)が入っています。書き込みのみ遅延が大きい場合はWALやジャーナルの書き込みパターンが疑われます。 - ステップ3: キューの滞留確認 —
tracepoint:block:block_bio_queueとblock_rq_issueの間隔を見ることで、マルチキューブロック層(blk-mq)内でのキュー待ち時間が可視化できます。 - ステップ4: I/Oスケジューラの確認 —
cat /sys/block/sda/queue/schedulerで現在のスケジューラを確認します。mq-deadlineやnoneはNVMe向け、bfqはHDDや混合ワークロードに使われることが多いですが、環境によって適合が異なります。 - ステップ5: デバイス自体の診断 —
smartctl -a /dev/sdaでS.M.A.R.T.情報を確認し、リアロケーションカウントや保留中セクタ数に異常値がないかを見ます。
各ステップでbpftraceが「ブロック層には問題がない」という結果を示した場合、問題はファイルシステム層(ext4/XFSのジャーナルロック、メタデータ更新の競合)かVFS層にある可能性が高くなります。その場合は tracepoint:ext4:* や tracepoint:xfs:* に切り替えて同様に調査します。
本番運用での注意点と切り戻し
bpftraceプロセスは明示的にkillするかCtrl-Cで終了させることでフックが解除されます。プロセスが異常終了した場合もカーネルのBPFサブシステムが自動でクリーンアップします。ただし、@start マップに大量のエントリが蓄積した状態でkillすると、カーネル側のBPFマップ解放に一瞬のレイテンシが出ることがあります。長時間の診断後は clear(@start) を END ブロックに入れておくことが推奨です(上記スクリプトには既に含まれています)。
よくあるつまずきとして、@start マップのキーに dev と sector の組を使っているにもかかわらず、同一デバイスで同一セクタへのI/Oが短時間に重なるとマップの値が上書きされ、レイテンシが実際より短く見える場合があります。これはNVMeの並列キューが有効な環境でランダムI/Oが多い場合に起きやすいです。より厳密に計測したい場合はリクエストポインタをキーにする方法もありますが、kprobeが必要になるため安定性とのトレードオフがあります。
診断スクリプトは本番ホストに直接置かず、踏み台サーバや監視サーバからSSH経由で転送・実行し、終了後に削除するフローにすると変更管理の観点からも扱いやすくなります。
2026年現行環境での差分と動向
カーネル6.6以降ではblk-mqのデフォルトスケジューラがNVMeで none、SATAで mq-deadline となっており、キュー深度の挙動が以前と変わっています。5系カーネル時代の設定をそのまま引き継いでいる環境では、スケジューラのチューニング余地がなくなっているケースもあります。bpftraceの診断結果をもとにスケジューラを変更する際は、対象カーネルの実際の設定を確認してから判断してください。
またRHEL 9.4以降では bpftrace パッケージが公式リポジトリに含まれており、dnf install bpftrace で0.21系が導入できます。Ubuntu 24.04 LTSは apt install bpftrace で0.20系が入ります。いずれもカーネル6.x対応が安定しており、tracepoint:block:* の主要フィールドは正常に取得できることを確認されています。
eBPF/bpftraceの周辺ツールエコシステムとしてはBCC(BPF Compiler Collection)のツール群も引き続き活用されており、biolatency・biotop はbpftraceスクリプトよりも手軽にデバイス単位の統計を得る手段として有用です。単純な傾向把握にはBCCツールを使い、より細かいフィルタリングや独自集計が必要になった段階でbpftraceスクリプトを書くという使い分けが実務ではよく見られます。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
PR・広告
[試して理解]Linuxのしくみ 増補改訂版(Amazon)
プロセス・権限・ファイルシステムなどLinux内部を図解で理解できる一冊。運用判断の勘所に。
※ Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。
