著者の関心対象である、クラウド上のソフトウェアを運用するオペレーターの観点で、トレーシングにおけるBPFを位置づける。
マイクロサービスアーキテクチャやコンテナオーケストレーションの普及などの要因により、クラウド上に展開されたアプリケーションの複雑化が加速している。そのため、システムのオペレーターは、システムの内部状態を把握することが難しくなっている。内部状態を知るために、システムの上位層ではAPM(Application Performance Management)や分散トレーシングといった、アプリケーションの知識を用いたトレーシング技術が発展している。その一方で、システムの下位層、コンテナやミドルウェアのようにOSカーネルの機能を直接呼び出すシステムの下位層の内部状態も把握する必要がある。
システムの下位層の状態を知るには、従来より、Linuxカーネルが標準で提供するprocfsやsysfsからファイル読み込み操作によりメトリックを取得することが一般的である。シェルの対話環境でデータを閲覧するのであれば、[Linuxサーバにログインしたらいつもやっているオペレーション - ゆううきブログ](https://blog.yuuk.io/entry/linux-server-operations)や[Linux Performance Analysis in 60,000 Milliseconds | by Netflix Technology Blog | Netflix TechBlog](https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55)のように、古典的なコマンドを駆使する。データを蓄積するのであれば、データ収集用の常駐プロセスが中央のストレージへデータを送信する。サーバ監視サービス[Mackerel](https://mackerel.io)の場合、[mackerel-agent](https://github.com/mackerelio/mackerel-agent)と呼ばれる常駐プロセスがprocfsから直接値を読み込むか、コマンド出力を読み込んでいる。[GitHub - mackerelio/go-osstat: OS system statistics library for Go](https://github.com/mackerelio/go-osstat/)
これらのメトリックが示すものは、ハードウェアリソースの合計の使用量など限定的なものである。例えば、通信先のIPアドレスごとのネットワーク使用帯域を取得することはできない。また、数値データとしてのメトリックの取得以外に、カーネル内のスタックトレースなどプロファイリングのための出力を得ることもできない。そのため、Linuxではカーネルの内部状態をトレースするための技術(perf、ftrace、SystemTap、kprobe、uprobe、DTrace、straceなど)が古くから存在している。Linuxのトレーシング技術は、[Linuxカーネルのドキュメント](https://www.kernel.org/doc/html/latest/trace/index.html)にまとめられている。その他、[Julia Evansによるブログポスト](https://jvns.ca/blog/2017/07/05/linux-tracing-systems/)、[Jake EdgeによるLWNのポスト](https://jvns.ca/blog/2017/07/05/linux-tracing-systems/)日本語では[mm_iさんによる記事](https://mmi.hatenablog.com/entry/2018/03/04/052249)で各種トレーシング技術が視覚的に整理されている。歴史的な事情もあり、Linuxのトレーシングの各要素技術間の関係性は複雑なものとなっている。
これらのトレーシングツールは、機能が制限されているため、カーネル内の任意の複雑な構造を参照できず、カスタムのロジックを書くことが難しい。また、カーネル内でイベントが発生すると、カーネル内のバッファ経由で全てのイベントのレコードがユーザ空間のツールに送られ、ツールがレコードを解析する。そのためイベントの流量が大きい場合、カーネルからユーザ空間への転送負荷が課題となる。
従来のカーネル拡張機構である**カーネルモジュール**はカーネルのイベントソースやAPIにアクセスできるため、カーネルモジュールにより、カーネル内でイベントをフィルタリング・集約することにより、ユーザ空間へのイベントの転送負荷を抑えることも可能である。モニタリングツールの[draios/sysdig](https://github.com/draios/sysdig)は現在ではBPFで実装されているが、以前はカーネルモジュールが使用されていた。しかし、カーネルモジュールはバグ(カーネルパニック)やセキュリティの脆弱性を防ぐ機構をもたないため、安全性に課題がある。また、カーネルに含まれる不安定なABIを呼び出すこともできるため、カーネルバージョン間の移植性にも課題がある<sup id="a2">[2](#f2)</sup>。Sysdig社のブログ記事での同様の指摘がある。[Sysdig and Falco now powered by eBPF. – Sysdig](https://sysdig.com/blog/sysdig-and-falco-now-powered-by-ebpf/)
BPFは専用の仮想マシン用の命令で記述されたコードを専用の検査器が検査した上で、仮想マシンがコードを解釈するアーキテクチャをとる。これにより、カーネル内で安全なサンドボックス化された、ユーザーのカスタムプログラムを実行できる。仮想マシン用の命令セットや仮想マシンから呼び出し可能なカーネル機能へのインターフェイスはカーネル開発者により安定して維持されるため、移植性が高い。BPFにおいても、カーネル内でイベントをフィルタリング・集約したのちにユーザ空間へ転送させることができる。筆者の研究にて、カーネル内のデータの集約により、CPU負荷が低減されることを一例として確認している。[分散アプリケーションの依存発見に向いたTCP/UDPソケットに基づく低負荷トレーシング - ゆううきブログ](https://blog.yuuk.io/entry/2021/wsa08)
次の図に、BPFトレーシングの構成を示しておく。
![[Pasted image 20211228154758.png]]