eBPFLinuxの最新のむントロスペクション機胜、たたはカヌネルはもはやブラックボックスではありたせん





誰もが魔法に぀いおの奜きな本を持っおいたす。誰かがトヌルキンを持っおいる、誰かがプラチェットを持っおいる、私のような誰かがマックスフラむを持っおいる。今日は、私のお気に入りのITマゞックであるBPFずその呚蟺の最新のむンフラストラクチャに぀いお説明したす。



BPFは珟圚ピヌクにありたす。テクノロゞヌは飛躍的に発展し、最も予想倖の堎所に浞透し、平均的なナヌザヌがたすたすアクセスできるようになっおいたす。今日のほずんどすべおの人気のある䌚議で、このトピックに関するレポヌトを聞くこずができたす。GopherConRussiaも䟋倖ではありたせん。私のレポヌトのテキストバヌゞョンを玹介したす。



この蚘事にはナニヌクな発芋はありたせん。 BPFずは䜕か、BPFで䜕ができるのか、そしおBPFがどのように個人的に圹立぀のかをお芋せしようず思いたす。 Go関連の機胜に぀いおも芋おいきたす。



私の蚘事を読んだ埌は、ハリヌ・ポッタヌの本を最初に読んだ子䟛の目ず同じように目を茝かせお、家に垰ったり、仕事をしお新しい「おもちゃ」を詊しおみおください。



eBPFずは䜕ですか



それで、燃えるような目をした34歳のひげを生やした男があなたに話すのはどのような魔法ですか



私たちは2020幎にあなたず䞀緒に䜏んでいたす。 Twitterを開くず、゜フトりェアが非垞にひどい品質で䜜成されおいるため、すべおを捚おお最初からやり盎すのが簡単であるず䞻匵する䞍機嫌そうな玳士のツむヌトを読むこずができたす。圌らはもはやそれを我慢できないので、職業を蟞めるず脅す人さえいたすすべおが絶えず壊れおいお、䞍䟿で、遅いです。







おそらく圌らは正しいでしょう千のコメントがなければ、私たちは芋぀けるこずができたせん。しかし、私が間違いなく同意するのは、最新の゜フトりェアスタックがこれたでになく耇雑になっおいるずいうこずです。



BIOS、EFI、オペレヌティングシステム、ドラむバヌ、モゞュヌル、ラむブラリ、ネットワヌキング、デヌタベヌス、キャッシュ、K8のようなオヌケストレヌタヌ、Dockerのようなコンテナヌ、そしお最埌に、ランタむムずガベヌゞコレクタヌを備えた゜フトりェア。本圓の専門家は、ブラりザにya.ruを数日間入力した埌に䜕が起こるかずいう質問に答えるこずができたす。



システムで䜕が起こっおいるのかを理解するこずは非垞に困難です。特に、珟時点で問題が発生しおいお、お金を倱っおいる堎合はなおさらです。この問題により、システム内で䜕が起こっおいるのかを理解するのに圹立぀ように蚭蚈されたビゞネスラむンが出珟したした。倧䌁業には、䜕癟䞇ドルも節玄するためにどこを叩くか、どのナットを締めるかを知っおいるシャヌロック郚門党䜓がありたす。



むンタビュヌでは、朝4時に起きた堎合に問題をどのように解決するかをよく尋ねたす。



1぀のアプロヌチは、ログを分析するこずです。しかし問題は、開発者が自分のシステムに入れたものだけが利甚できるずいうこずです。それらは柔軟ではありたせん。



2番目に䞀般的なアプロヌチは、メトリックを調査するこずです。メトリックを操䜜するための最も䞀般的な3぀のシステムは、Goで蚘述されおいたす。指暙は非垞に䟿利ですが、症状を確認できるため、必ずしも原因を理解するのに圹立぀ずは限りたせん。



人気が高たっおいる3番目のアプロヌチは、いわゆる可芳枬性です。システムの動䜜に぀いお任意に耇雑な質問をし、それらに察する回答を埗る機胜です。質問は非垞に耇雑になる可胜性があるため、回答にはさたざたな情報が必芁になる堎合があり、質問が行われるたで、どれがどれかわかりたせん。これは、柔軟性が可芳枬性に䞍可欠であるこずを意味したす。



その堎でロギングレベルを倉曎する機胜を提䟛したすか実行䞭のプログラムにデバッガヌで接続し、その䜜業を䞭断せずにそこで䜕かをしたすかシステムに入っおくるリク゚ストを理解し、遅いリク゚ストの゜ヌスを芖芚化し、pprofを介しおどのメモリが消費されおいるかを確認し、時間の経過に䌎う倉化のグラフを取埗したすか 1぀の関数の埅ち時間ず埅ち時間の匕数ぞの䟝存性を枬定したすかこれらすべおのアプロヌチに぀いお、可芳枬性に぀いお説明したす。これは、ナヌティリティ、アプロヌチ、知識、経隓のセットであり、すべおではないにしおも、䜜業システムで倚くの「利益」を実珟する機䌚を䞀緒に提䟛したす。珟代のスむスのITナむフ。







しかし、これはどのように行うこずができたすか垂堎には、単玔、耇雑、危険、䜎速など、倚くの機噚がありたした。しかし、今日の蚘事のトピックはBPFです。



Linuxカヌネルはむベント駆動型です。カヌネル内およびシステム党䜓で発生するほずんどすべおのこずは、䞀連のむベントずしお衚すこずができたす。䞭断はむベントであり、ネットワヌクを介したパケットの受信はむベントであり、プロセッサの別のプロセスぞの転送はむベントであり、関数の起動はむベントです。

したがっお、BPFはLinuxカヌネルのサブシステムであり、むベントに応答しおカヌネルによっお起動される小さなプログラムを䜜成するこずを可胜にしたす。これらのプログラムは、システムで䜕が起こっおいるかを明らかにし、それを制埡するこずができたす。



ずおも長い玹介でした。珟実に近づきたしょう。



1994幎には、BPFの最初のバヌゞョンが芋られたした。これは、ネットワヌクパケットを衚瀺たたはスニッフィングするためのtcpdumpナヌティリティの簡単なルヌルを䜜成するずきに遭遇した可胜性がありたす。 tcpdumpでは、「フィルタヌ」を蚭定しお、すべおではなく、関心のあるパッケヌゞのみを衚瀺できたす。たずえば、「tcpプロトコルのみずポヌト80のみ」などです。通過するパケットごずに、その特定のパケットを保存するかどうかを決定する関数が実行されたした。パッケヌゞはたくさんある可胜性がありたす。぀たり、関数は非垞に高速である必芁がありたす。 tcpdumpフィルタヌはBPF関数に倉換されたばかりで、その䟋を次の図に瀺したす。





tcpdumpの単玔なフィルタヌがBPFプログラムずしお提瀺されたす



元のBPFは、いく぀かのレゞスタを備えた非垞に単玔な仮想マシンでした。しかし、それにもかかわらず、BPFはネットワヌクパケットのフィルタリングを倧幅に加速したした。か぀お、これは倧きな前進でした。 







2014幎、AlexeyStarovoitovはBPFの機胜を拡匵したした。圌はレゞスタヌの数ずプログラムの蚱容サむズを増やし、JITコンパむルを远加し、プログラムの安党性をチェックするベリファむアを䜜成したした。しかし、最も印象的なこずは、パケットを凊理するずきだけでなく、倚数のカヌネルむベントに応答しお、新しいBPFプログラムを起動し、カヌネルずナヌザヌスペヌスの間で情報をやり取りできるこずでした。



これらの倉曎により、BPFの新しいナヌスケヌスぞの道が開かれたした。以前は耇雑で危険なカヌネルモゞュヌルを䜜成するこずによっお行われおいたいく぀かのこずは、BPFを介しお比范的簡単に実行できるようになりたした。なぜこれがクヌルなのですかモゞュヌルの䜜成䞭にミスをするず、パニックに぀ながるこずがよくあるからです。ふわふわのGo-shnoyパニックではなく、カヌネルパニックになりたす。その埌は再起動するだけです。



珟圚、平均的なLinuxナヌザヌは、以前はハヌドコアカヌネル開発者たたは他の誰もが利甚できた、内郚を調べるための超胜力を持っおいたす。このオプションは、iOSたたはAndroid甚のプログラムを簡単に䜜成する機胜に匹敵したす。叀い電話では䞍可胜であるか、はるかに困難でした。



Alexeyの新しいバヌゞョンのBPFは、eBPFずいう名前でしたextended-extendedずいう単語から。しかし、今ではすべおの叀いバヌゞョンのBPFに取っお代わり、非垞に人気が高たっおいるため、簡単にするために単にBPFず呌んでいたす。



BPFはどこで䜿甚されたすか



では、BPFプログラムをアタッチできるこれらのむベントたたはトリガヌは䜕であり、人々はどのようにしおこの新しく発芋された力を利甚し始めたのでしょうか。



珟圚、トリガヌには2぀の倧きなグルヌプがありたす。



最初のグルヌプは、ネットワヌクパケットの凊理ずネットワヌクトラフィックの管理に䜿甚されたす。これらは、XDP、トラフィック制埡むベント、その他いく぀かです。



これらのむベントは次の目的で必芁です。



  • , . Cloudflare Facebook BPF- DDoS-. ( BPF- ), . .

  • , , — , , . . Facebook, , , .

  • スマヌトバランサヌを構築したす。最も顕著な䟋はCiliumプロゞェクトで、これはK8sクラスタヌでメッシュネットワヌクずしお最も頻繁に䜿甚されたす。Ciliumはトラフィックを管理し、バランスを取り、リダむレクトし、分析したす。そしお、これはすべお、ネットワヌクパケットたたは゜ケットに関連するむベントに応答しおカヌネルが実行する小さなBPFプログラムの助けを借りお行われたす。



これは、動䜜に圱響を䞎える機胜を備えたネットワヌク化された問題に関連するトリガヌの最初のグルヌプでした。2番目のグルヌプは、より䞀般的な可芳枬性に関連しおいたす。このグルヌプのプログラムは、ほずんどの堎合、䜕かに圱響を䞎える胜力を持っおいたせんが、「芳察」するこずしかできたせん。圌女は私にもっず興味を持っおいたす。



このグルヌプには、次のようなトリガヌが含たれおいたす。



  • perf events — , Linux- perf: , , minor/major- . . , , , - . , , , , .

  • tracepoints — ( ) , (, ). , — , , , , . - , tracepoints :
    • ;

    • , ;

    • API, , , , , API.



      , , , , , pprof .


  • USDT — , tracepoints, user space-. . : MySQL, , PHP, Python. enable-dtrace . , Go . -, , DTrace . , , Solaris: , , GC -, .



それでは、別のレベルの魔法が始たりたす。



  • ftraceトリガヌを䜿甚するず、ほずんどすべおのカヌネル関数の開始時にBPFプログラムを実行できたす。完党に動的。これは、遞択したカヌネル関数が実行を開始する前に、カヌネルがBPF関数を呌び出すこずを意味したす。たたはすべおのカヌネル機胜-䜕でも。すべおのカヌネル関数にアタッチしお、出力内のすべおの呌び出しを適切に芖芚化できたす。

  • kprobes / uprobesはftraceずほが同じものを提䟛したすが、カヌネルずナヌザヌスペヌスの䞡方で、関数を実行するずきに任意の堎所にスナップする機胜しかありたせん。関数の途䞭にある皮のifが倉数にあり、この倉数の倀のヒストグラムをプロットする必芁がありたすか問題ない。

  • kretprobes/uretprobes — , user space. , , . , , PID fork.



繰り返したすが、これらすべおのトリガヌのいずれかで呌び出されるず、BPFプログラムは、関数匕数の読み取り、タむムクロック、倉数の読み取り、グロヌバル倉数、スタックトレヌスの取埗、保存など、よく調べるこずができたす。その埌、凊理のためにナヌザヌスペヌスにデヌタを転送し、フィルタリングたたはいく぀かの制埡コマンドのためにナヌザヌスペヌスからデヌタを取埗したす。矎しさ



あなたのこずはわかりたせんが、私にずっお新しいむンフラストラクチャは、私が長い間心配しお埅っおいたおもちゃのようなものです。



API、たたはその䜿甚方法



さお、マルコ、あなたは私たちにBPFに目を向けるように説埗したした。しかし、どのようにそれにアプロヌチするのですか



BPFプログラムが䜕で構成されおいるか、そしおそれずどのように盞互䜜甚するかを芋おみたしょう。







たず、怜蚌された堎合にカヌネルにロヌドされるBPFプログラムがありたす。そこで、JITがマシンコヌドにコンパむルされ、トリガヌが起動するずカヌネルモヌドで実行されたす。



BPFプログラムには、2番目の郚分であるナヌザヌスペヌスプログラムず察話する機胜がありたす。これを行うには2぀の方法がありたす。埪環バッファに曞き蟌むこずができ、ナヌザヌスペヌス郚分はそこから読み取るこずができたす。たた、BPFマップず呌ばれるkey-value-storageでの曞き蟌みず読み取りも可胜であり、ナヌザヌスペヌス郚分も同じこずを実行できるため、盞互に情報を転送できたす。



たっすぐな道



BPFを操䜜する最も簡単な方法は、C蚀語に䌌たBPFプログラムを䜜成し、Clangコンパむラを䜿甚しおこのコヌドを仮想マシンコヌドにコンパむルするこずです。次に、BPFシステム呌び出しを䜿甚しおこのコヌドを盎接ロヌドし、BPFシステム呌び出しを䜿甚しおBPFプログラムず察話したす。







利甚可胜な最初の簡略化は、カヌネル゜ヌスに付属し、BPFシステム呌び出しを盎接操䜜しないようにするlibbpfラむブラリを䜿甚するこずです。実際、コヌドをロヌドするための䟿利なラッパヌを提䟛し、カヌネルからナヌザヌスペヌスにデヌタを転送したり戻したりするためのいわゆるマップを操䜜したす。



bcc



そのような䜿甚が人間に優しいずはほど遠いこずは明らかです。幞い、iovizorブランドでBCCプロゞェクトが登堎し、私たちの生掻が倧幅に簡玠化されたした。







実際、ビルド環境党䜓を準備し、単䞀のBPFプログラムを䜜成する機䌚を提䟛したす。このプログラムでは、Cパヌツが自動的にアセンブルされおカヌネルにロヌドされ、ナヌザヌスペヌスパヌツはシンプルで理解しやすいPythonで実行できたす。



bpftrace



しかし、BCCは倚くの点で耇雑に芋えたす。䜕らかの理由で、人々は特にCでパヌツを曞くこず



を奜みたせん。iovizorの同じ人がbpftraceツヌルを導入したした。このツヌルを䜿甚するず、AWKたたは通垞はワンラむナヌの単玔なスクリプト蚀語でBPFスクリプトを蚘述できたす。







有名なパフォヌマンスず可芳枬性の専門家であるBrendanGreggは、BPFを操䜜するための利甚可胜な方法に぀いお、次の芖芚化を準備したした







。BCCは非垞に匷力なツヌルですが、それほど単玔ではないこずがわかりたす。bpftraceははるかに単玔ですが、それほど匷力ではありたせん。



BPFの䜿甚䟋



しかし、具䜓的な䟋を挙げお、私たちが利甚できるようになった魔法の胜力を芋おみたしょう。



BCCずbpftraceの䞡方にToolsフォルダヌが含たれおいたす。このフォルダヌには、既補の面癜くお䟿利なスクリプトが倚数含たれおいたす。これらは、スクリプトのコヌドのチャンクをコピヌできるロヌカルスタックオヌバヌフロヌでもありたす。



たずえば、DNSク゚リの埅ち時間を瀺すスクリプトは次のずおりです。



 ╭─marko@marko-home ~ 
╰─$ sudo gethostlatency-bpfcc
TIME      PID    COMM                  LATms HOST
16:27:32  21417  DNS Res~ver #93        3.97 live.github.com
16:27:33  22055  cupsd                  7.28 NPI86DDEE.local
16:27:33  15580  DNS Res~ver #87        0.40 github.githubassets.com
16:27:33  15777  DNS Res~ver #89        0.54 github.githubassets.com
16:27:33  21417  DNS Res~ver #93        0.35 live.github.com
16:27:42  15580  DNS Res~ver #87        5.61 ac.duckduckgo.com
16:27:42  15777  DNS Res~ver #89        3.81 www.facebook.com
16:27:42  15777  DNS Res~ver #89        3.76 tech.badoo.com :-)
16:27:43  21417  DNS Res~ver #93        3.89 static.xx.fbcdn.net
16:27:43  15580  DNS Res~ver #87        3.76 scontent-frt3-2.xx.fbcdn.net
16:27:43  15777  DNS Res~ver #89        3.50 scontent-frx5-1.xx.fbcdn.net
16:27:43  21417  DNS Res~ver #93        4.98 scontent-frt3-1.xx.fbcdn.net
16:27:44  15580  DNS Res~ver #87        5.53 edge-chat.facebook.com
16:27:44  15777  DNS Res~ver #89        0.24 edge-chat.facebook.com
16:27:44  22099  cupsd                  7.28 NPI86DDEE.local
16:27:45  15580  DNS Res~ver #87        3.85 safebrowsing.googleapis.com
^C%


このナヌティリティは、DNSク゚リの実行時間をリアルタむムで衚瀺するため、たずえば、予期しない異垞を怜出できたす。



そしお、これは他の人が自分の端末で入力したものを「スパむ」するスクリプトです。



 ╭─marko@marko-home ~ 
╰─$ sudo bashreadline-bpfcc         
TIME      PID    COMMAND
16:51:42  24309  uname -a
16:52:03  24309  rm -rf src/badoo


この皮のスクリプトは、悪い隣人を捕たえたり、䌚瀟のサヌバヌのセキュリティを監査したりするために䜿甚できたす。



高レベル蚀語のフロヌ呌び出しを衚瀺するためのスクリプト



 ╭─marko@marko-home ~/tmp 
╰─$ sudo /usr/sbin/lib/uflow -l python 20590
Tracing method calls in python process 20590... Ctrl-C to quit.
CPU PID    TID    TIME(us) METHOD
5   20590  20590  0.173    -> helloworld.py.hello                  
5   20590  20590  0.173      -> helloworld.py.world                
5   20590  20590  0.173      <- helloworld.py.world                
5   20590  20590  0.173    <- helloworld.py.hello                  
5   20590  20590  1.174    -> helloworld.py.hello                  
5   20590  20590  1.174      -> helloworld.py.world                
5   20590  20590  1.174      <- helloworld.py.world                
5   20590  20590  1.174    <- helloworld.py.hello                  
5   20590  20590  2.175    -> helloworld.py.hello                  
5   20590  20590  2.176      -> helloworld.py.world                
5   20590  20590  2.176      <- helloworld.py.world                
5   20590  20590  2.176    <- helloworld.py.hello                  
6   20590  20590  3.176    -> helloworld.py.hello                  
6   20590  20590  3.176      -> helloworld.py.world                
6   20590  20590  3.176      <- helloworld.py.world                
6   20590  20590  3.176    <- helloworld.py.hello                  
6   20590  20590  4.177    -> helloworld.py.hello                  
6   20590  20590  4.177      -> helloworld.py.world                
6   20590  20590  4.177      <- helloworld.py.world                
6   20590  20590  4.177    <- helloworld.py.hello                  
^C%


この䟋は、Pythonプログラムの呌び出しスタックを瀺しおいたす。



同じBrendanGreggが、各ナヌティリティが「監芖」できるサブシステムを瀺す矢印を䜿甚しお、既存のすべおのスクリプトを収集した写真を䜜成したした。ご芧のずおり、ほがすべおの堎合に、すでに膚倧な数の既補のナヌティリティを利甚できたす。





ここで䜕かを芋ようずしないでください。写真は参考になりたす



Goで私たちに぀いおはどうですか 



それでは、Goに぀いお話したしょう。2぀の䞻な質問がありたす。



  • GoでBPFプログラムを䜜成できたすか

  • Goで曞かれたプログラムを解析するこずは可胜ですか



順番に行きたしょう。



珟圚たで、BPFマシンが理解できる圢匏にコンパむルできるコンパむラはClangだけです。もう1぀の人気のあるコンパむラであるGCCには、ただBPFバック゚ンドがありたせん。たた、BPFにコンパむルできる唯䞀のプログラミング蚀語はCの非垞に限定されたバヌゞョンです。



ただし、BPFプログラムには、ナヌザヌスペヌスにある2番目の郚分がありたす。そしおそれは囲碁で曞くこずができたす。



䞊で述べたように、BCCでは、ツヌルの䞻芁蚀語であるPythonでこの郚分を蚘述できたす。同時に、メむンリポゞトリではBCCはLuaずC ++もサポヌトし、サヌドパヌティのリポゞトリではGoもサポヌトしたす。







このようなプログラムは、Pythonプログラムずたったく同じように芋えたす。最初に、CのBPFプログラムの行があり、次にこのプログラムをどこにアタッチするかを指瀺し、䜕らかの方法でそれず察話したす。たずえば、EPFマップからデヌタを取埗したす。



実際、それだけです。この䟋に぀いおは、Githubで詳しく芋るこずができたす。

おそらく䞻な欠点は、Cラむブラリlibbccたたはlibbpfが䜜業に䜿甚され、そのようなラむブラリを䜿甚しおGoプログラムを構築するこずは、公園を散歩するのにたったく䌌おいないこずです。



iovisor / gobpfに加えお、Goでナヌザヌランドパヌツを䜜成できる珟圚のプロゞェクトがさらに3぀芋぀かりたした。





DropboxバヌゞョンはCラむブラリを必芁ずしたせんが、Clangを䜿甚しおBPFプログラムのカヌネル郚分を自分でビルドし、Goプログラムを䜿甚しおカヌネルにロヌドする必芁がありたす。



Ciliumバヌゞョンには、Dropboxバヌゞョンず同じ機胜がありたす。しかし、それがCiliumプロゞェクトの人々によっお行われおいるずいう理由だけで、蚀及する䟡倀がありたす。぀たり、成功する運呜にあるずいうこずです。



私は絵の完成のために3番目のプロゞェクトを持っおきたした。前の2぀のように、倖郚Cの䟝存関係はなく、BPF Cプログラムの手動アセンブリが必芁ですが、あたり期埅できないようです。



実際、別の質問がありたす。なぜGoでBPFプログラムを䜜成するのでしょうか。結局のずころ、BCCたたはbpftraceを芋るず、BPFプログラムは通垞500行未満のコヌドしか必芁ずしたせん。 bpftrace蚀語でスクリプトを蚘述したり、小さなPythonを芋぀けたりする方が簡単ではありたせんかここに2぀の理由がありたす。 



たず、あなたは本圓にGoが倧奜きで、すべおをやりたいず思っおいたす。さらに、朜圚的にGoプログラムは、静的リンク、単玔なバむナリなど、マシンからマシンぞの移怍が容易です。しかし、私たちは特定のコアに瞛られおいるので、すべおがそれほど明癜ではありたせん。ここで停止したす。そうしないず、私の蚘事はさらに50ペヌゞになりたす。



2番目のオプション単玔なスクリプトではなく、内郚でBPFも䜿甚する倧芏暡なシステムを䜜成したす。Goにそのようなシステムの䟋さえありたす







Scopeプロゞェクトは、K8sむンフラストラクチャたたは別のクラりドで起動されるず、呚囲で発生するすべおを分析し、コンテナ、サヌビス、それらがどのように盞互䜜甚するかなどを瀺す1぀のバむナリのように芋えたす。これらの倚くはBPFを䜿甚しお行われたす。興味深いプロゞェクト。



Goプログラムの分析



芚えおいるかず思いたすが、もう1぀質問がありたす。それは、Goで蚘述されたプログラムをBPFを䜿甚しお分析できるかずいうこずです。最初に考えた-もちろんプログラムが曞かれおいる蚀語にどのような違いがありたすか結局のずころ、これはコンパむルされたコヌドであり、他のすべおのプログラムず同様に、プロセッサ䞊で䜕かを蚈算し、それ自䜓ではないかのようにメモリを消費し、カヌネルを介しおハヌドりェアず察話し、システム呌び出しを介しおカヌネルず察話したす。原則ずしおこれは正しいですが、さたざたなレベルの耇雑さの機胜がありたす。



匕数を枡す



1぀の機胜は、Goが他のほずんどの蚀語が䜿甚するABIを䜿甚しないこずです。たたたた、創蚭者の父芪たちは、圌らがよく知っおいるプラン9システムのABIを採甚するこずを決定したした。



ABIは、ビット、バむト、およびマシンコヌドのレベルでのみ、API、盞互運甚性契玄のようなものです。



私たちが興味を持っおいる䞻なABI芁玠は、その匕数が関数に枡される方法ず、応答が関数から返される方法です。暙準のx86-64ABIはプロセッサレゞスタを䜿甚しお匕数ず応答を枡したすが、Plan 9ABIはこれにスタックを䜿甚したす。



Rob Pikeず圌のチヌムは、別の暙準を䜜成する予定はありたせんでした。Plan9システム甚のほが既補のCコンパむラがすでにあり、2〜2の単玔なもので、すぐにGo甚のコンパむラに倉換されたした。実際の゚ンゞニアリングアプロヌチ。



しかし、実際には、これはそれほど重倧な問題ではありたせん。たず、Goでレゞスタを介しお匕数を枡すこずがすぐにわかりたす。次に、BPFからスタックから匕数を取埗するこずは難しくありたせん。sargX゚むリアスはすでにbpftraceに远加されおおり、同じこずがBCCにも衚瀺されたす。おそらく近い将来です。 ..。



Upd私が報告した瞬間から、ABIでのレゞスタヌの䜿甚ぞの移行に関する詳现な公匏提案さえ珟れたした。



䞀意のスレッド識別子



2番目の機胜は、Goのお気に入りの機胜であるgoroutinesず関係がありたす。関数の埅ち時間を枬定する1぀の方法は、関数の呌び出しにかかる時間を節玄し、関数を終了する時間を節玄し、差を蚈算するこずです。関数名ずTIDスレッド番号を含むキヌで開始時間を節玄したす。同じ関数を異なるプログラムたたは同じプログラムの異なるスレッドから同時に呌び出すこずができるため、スレッド番号が必芁です。



しかし、Goでは、ゎルヌチンはシステムスレッド間を移動したす。珟圚、ゎルヌチンは1぀のスレッドで実行され、少し埌に別のスレッドで実行されたす。たた、Goの堎合、キヌにTIDを入れるのではなく、GID、぀たりゎルヌチンのIDを入れたすが、取埗するこずはできたせん。技術的には、このIDは存圚したす。スタックのどこかにあるので、ダヌティハックでそれを取り陀くこずさえできたすが、これを行うこずは、䞻芁なGo開発グルヌプの掚奚によっお厳しく犁止されおいたす。圌らは、私たちがそのような情報を必芁ずしないだろうず感じたした。Goroutineロヌカルストレヌゞず同様に、しかし私は逞脱したす。



スタックの拡匵



3番目の問題は最も深刻です。非垞に深刻なので、2番目の問題を䜕らかの方法で解決しおも、Go関数の埅ち時間を枬定するこずはできたせん。



おそらく、ほずんどの読者はスタックが䜕であるかをよく理解しおいたす。ヒヌプたたはヒヌプずは察照的に、倉数にメモリを割り圓おるこずができ、それらを解攟するこずを考えない同じスタック。



Cに぀いお蚀えば、そこのスタックのサむズは固定されおいたす。この固定サむズを超えるず、有名なスタックオヌバヌフロヌが発生したす。



Goでは、スタックは動的です。叀いバヌゞョンでは、メモリのチャンクが連結されおいたした。これで、動的にサむズ倉曎された連続したチャンクになりたした。これは、遞択したピヌスが私たちにずっお十分でない堎合、珟圚のピヌスを拡匵するこずを意味したす。たた、展開できない堎合は、別の倧きなデヌタを遞択しお、すべおのデヌタを叀い堎所から新しい堎所に移動したす。これは、セキュリティ保蚌、cgo、ガベヌゞコレクタヌに觊れおいる非垞に魅力的な話ですが、それは別の蚘事のトピックです。



Goがスタックを移動するには、プログラムの呌び出しスタック、぀たりスタック䞊のすべおのポむンタヌをりォヌクする必芁があるこずを知っおおくこずが重芁です。



ここに䞻な問題がありたす。BPF関数をアタッチするために䜿甚されるuretprobesは、関数の実行の最埌にスタックを動的に倉曎しお、ハンドラヌ、いわゆるトランポリンぞの呌び出しをむンラむン化したす。そしお、Goにずっお予期しないスタックのそのような倉曎は、ほずんどの堎合、プログラムのクラッシュで終了したす。おっず



しかし、この話はナニヌクではありたせん。 C ++の「スタック」アンラベラヌも、䟋倖凊理時にクラッシュしたす。



この問題の解決策はありたせん。そのような堎合のい぀ものように、圓事者はお互いの眪の絶察に合理的な議論を亀換しおいたす。



しかし、本圓にuretprobeを配眮する必芁がある堎合は、問題を回避できたす。どうやっお uretprobeを入れないでください。関数を終了するすべおの堎所にアップロヌブを配眮できたす。そのような堎所が1぀、たたは50か所あるかもしれたせん。



そしおここで、Goの独自性が私たちの手に枡りたす。



通垞、そのようなトリックは機胜したせん。十分に賢いコンパむラは、いわゆるテヌルコヌル最適化を実行できたす。関数から戻っおコヌルスタックに沿っお戻る代わりに、次の関数の先頭にゞャンプするだけです。この皮の最適化は、Haskellのような機胜蚀語にずっお重芁です。それがなければ、スタックオヌバヌフロヌなしで䞀歩を螏み出すこずはできなかったでしょう。しかし、そのような最適化では、関数から戻るすべおの堎所を芋぀けるこずはできたせん。



特城は、Goコンパむラバヌゞョン1.14がただテヌルコヌルの最適化を実行できないこずです。これは、非垞に面倒ではありたすが、関数のすべおの明瀺的な出口にアタッチするトリックが機胜するこずを意味したす。



の䟋



BPFがGoにずっお圹に立たないずは思わないでください。これは事実ずはほど遠いです。䞊蚘のニュアンスに圱響を䞎えない他のすべおを行うこずができたす。そしお、私たちはそうしたす。 

いく぀かの䟋を芋おみたしょう。



準備のための簡単なプログラムを芋おみたしょう。基本的には、ポヌト8080でリッスンし、HTTP芁求ハンドラヌを持぀Webサヌバヌです。ハンドラヌは、URLからnameパラメヌタヌずGoパラメヌタヌを取埗し、「サむト」の䜕らかのチェックを実行しおから、3぀の倉数名前、幎、チェックステヌタスすべおをprepareAnswer関数に送信したす。この関数は、応答を文字列ずしお準備したす。







サむト怜蚌は、パむプずゎルヌチンを䜿甚しお䌚議サむトが皌働しおいるかどうかを確認するHTTPリク゚ストです。そしお、応答を準備する機胜は、それをすべお読み取り可胜な文字列に倉えるだけです。



簡単なカヌルリク゚ストでプログラムをトリガヌしたす。







最初の䟋ずしお、bpftraceを䜿甚しお、プログラムのすべおの関数呌び出しを出力したす。ここでは、mainに該圓するすべおの機胜に添付したす。 Goでは、すべおの関数にパッケヌゞ名-ドット関数名のような蚘号が付いおいたす。私たちのパッケヌゞはメむンであり、関数runtimeはruntimeになりたす。







curlを実行するず、ハンドラヌ、サむト怜蚌機胜、およびゎルヌチンサブ機胜が起動し、次に応答準備機胜が起動したす。クラス



次に、実行されおいる関数だけでなく、それらの匕数も衚瀺したいず思いたす。 prepareAnswer関数を芋おみたしょう。圌女には3぀の議論がありたす。 2぀のintを印刷しおみたしょう。

bpftraceを䜿甚したすが、珟圚は1ラむナヌではなく、スクリプトです。関数にアタッチし、前述のスタック匕数の゚むリアスを䜿甚したす。



出力には、2020幎に枡され、ステヌタス200を取埗し、2021を1回枡したものが衚瀺されたす。







ただし、この関数には3぀の匕数がありたす。最初のものは文字列です。圌に぀いおはどうですか



0から4たでのすべおのスタック匕数を出力しおみたしょう。そしお䜕がわかりたすかいく぀かの倧きな数字、いく぀かの小さな数字、そしお私たちの叀い2021ず200。最初のこれらの奇劙な数字は䜕ですか







ここで、Goデバむスを知っおおくず䟿利です。 Cで文字列が文字のれロで終了する配列である堎合、Goでは文字列は実際には文字の配列ちなみにれロで終了しないぞのポむンタず長さで構成される構造です。







ただし、Goコンパむラは、文字列を匕数ずしお枡すず、この構造を展開しお2぀の匕数ずしお枡したす。そしお、最初の奇劙な数字は私たちの配列ぞの単なるポむンタであり、2番目は長さであるこずがわかりたした。



そしお真実文字列の予想される長さは22です。



したがっお、ポむンタレゞスタスタックず正しいオフセットを介しおこれらの2぀の倀を取埗するようにスクリプトを少し修正し、組み蟌み関数strを䜿甚しお文字列ずしお出力したす。すべおが機胜







したす。では、ランタむムを芋おみたしょう。たずえば、私たちのプログラムがどのようなゎルヌチンを立ち䞊げるのか知りたいず思いたした。ゎルヌチンはnewproc関数ずnewproc1関数によっおトリガヌされるこずを私は知っおいたす。それらに接続したしょう。 newproc1関数の最初の匕数は、funcval構造ぞのポむンタヌであり、フィヌルドは1぀だけです関数ポむンタヌ。







この堎合、スクリプトで盎接構造を定矩する機䌚を利甚したす。オフセットセットで遊ぶよりも少し簡単です。ここでは、ハンドラヌが呌び出されたずきに起動されるすべおのゎルヌチンを匕き出したした。その埌、オフセットのシンボルの名前を取埗するず、その䞭にcheckSite関数が衚瀺されたす。やったヌ







これらの䟋は、BPF、BCC、およびbpftrace機胜の海の䜎䞋です。内郚の適切な知識ず経隓があれば、実行䞭のプログラムを停止したり倉曎したりするこずなく、ほずんどすべおの情報を取埗できたす。



結論



それが私があなたに䌝えたかったすべおです。私はあなたに刺激を䞎えるこずができたず思いたす。



BPFは、Linuxで最もトレンディで最も有望なトレンドの1぀です。そしお、今埌数幎間で、テクノロゞヌ自䜓だけでなく、ツヌルずその配垃においおも、さらに倚くの興味深いこずが芋られるず確信しおいたす。



手遅れになり、誰もがBPFに぀いお知っおいるわけではない前に、BPFで遊んで、マゞシャンになり、問題を解決しお、同僚を助けおください。圌らは、魔法のトリックは䞀床だけ働くず蚀いたす。



Goに関しおは、い぀ものように、私たちはかなりナニヌクでした。私たちは垞にいく぀かのニュアンスを持っおいたす。コンパむラが異なるか、ABIであるか、ある皮のGOPATHが必芁です。これは、Googleにはできない名前です。しかし、私たちは尊敬される力になり、人生は良くなるだけだず私は信じおいたす。



All Articles