Go プロセスが CPU コアを 100% 以上まで占有する場合、その原因は多くの場合、ホットなコードパスが CPU を消費していることにあります。実行中で未修正の Go チャットサービスを OpenResty XRay でプロファイリングしたところ、その高 CPU 使用率は正規表現のコンパイルにあることが判明しました。標準 regexp ライブラリの関数(業務関数 CheckMessage から prev_processor.go の 17 行目で呼び出される)が、CPU 時間の 36.8% を消費していたのです。正規表現のコンパイルはコストが高く、ホットなコードパスでは避けるべきです。

本記事では、コードの変更も再起動も不要なプロファイリングの全過程を、Go の高 CPU 使用率を観察する段階から、原因となる正確なソースファイルと行番号を特定する段階まで示します。

Go プロセスの高 CPU 使用率を観察する

top コマンドを実行すると、chat-service という名前の Go プロセスが CPU コアの 100% 以上を消費していることがわかります。(症状が逆の場合——リクエストが届き続けているのに CPU 使用率が低いままの場合——は、2% の CPU 使用率で停滞する Go プロセスの追跡をご覧ください。)

top コマンドが Go プロセス chat-service による CPU コア 100% 超の消費を示している

OpenResty XRay で Go の CPU 使用率をプロファイリングする

OpenResty XRay を使って、この未修正のプロセスをリアルタイムで分析します。特別なモジュールもコードの変更も再起動も必要ありません。Web コンソールで Guided Analysis(ガイド付き分析) ページに移動し、問題の種類として High CPU Usage(高 CPU 使用率) を選択します。OpenResty XRay は対象マシン上で実行中のアプリケーションを自動的に検出します。ドロップダウンからこの Go アプリケーションを選択します。

OpenResty XRay が実行中のアプリケーションを自動検出し、Go アプリケーションが選択されている

CPU を 96% 消費している特定のプロセス、つまり先ほど top で確認したプロセスを選択します。

CPU を 96% 消費している Go chat-service プロセスを分析対象として選択

言語レベルを Go に設定し、最大分析時間はデフォルトの 300 秒のままにします。分析を開始すると、システムは複数回のラウンドを実行しますが、この例では 2 回で十分です。

言語レベルが Go、最大分析時間が 300 秒に設定されている

CPU フレームグラフ分析

OpenResty XRay が自動的にレポートを生成します。

Go プロセス向けに OpenResty XRay が自動生成した CPU 分析レポート

このレポートには、最も多くの CPU 時間を消費している Go レベルのコードパスが表示されます。その中で最も割合が高いのは正規表現のコンパイルで、CPU 時間の 36.8% を占めています。

正規表現のコンパイルが CPU 消費の最上位(36.8%)であることを示すレポート

これは Go ランタイムの標準 regexp ライブラリにある 2 つの関数で、正規表現のコンパイルを担当しています。

正規表現のコンパイルを担当する標準 regexp ライブラリの 2 つの関数

この CheckMessage 関数は業務ロジックの一部であり、先ほど見た正規表現コンパイル関数を呼び出しています。

正規表現コンパイル関数を呼び出す CheckMessage 業務ロジック関数

Go のソースファイルと行番号を特定する

このコードパスをさらに詳しく知りたい場合は、More リンクをクリックします。

最もホットなコードパスの詳細分析を見るために More リンクをクリック

クリックすると、そのコードパスの詳細ビューが表示されます。これは Go レベルの CPU フレームグラフから導き出されたものです。

OpenResty XRay が生成した Go レベルの CPU フレームグラフ

ここには、このコードパスのパフォーマンスを改善する方法に関する説明と提案があります。

CPU ホットスポットに関する詳細な説明と最適化の提案

例えば、正規表現コンパイル関数はコストが高いため、可能な限り呼び出しを避けるべきだと述べています。

正規表現コンパイル関数のコストが高いことを指摘するレポート

続いて、正規表現を使用およびコンパイルする業務レベルの関数 CheckMessage について説明しています。

CheckMessage 業務関数とその正規表現コンパイルを説明するレポート

コンパイル済みの正規表現についても言及しています。

コンパイル済みの正規表現を説明するレポート

コードパスに戻り、CheckMessage という名前の Go 関数の緑色のボックスにマウスカーソルを合わせます。CheckMessage 関数の Go ソースファイルが表示され、ツールチップには prev_processor.go ファイルの完全なパスも表示されます。

CheckMessage 関数の prev_processor.go ソースファイルパスを示すツールチップ

Go ソースコードの行番号は 17 です。

フレームグラフのツールチップに表示された Go ソースコードの行番号 17

アイコンをクリックして、この関数の完全な Go ソースファイルパスをコピーします。

フレームグラフから完全な Go ソースファイルパスをコピー

先ほどコピーしたパスをターミナルに貼り付け、vim エディタで対応する Go の業務コードを表示します。お好みのエディタを自由にお使いいただけます。

vim エディタで Go ソースファイルを開く

レポートに表示されていた行番号どおり、17 行目に移動します。

Go ソースファイルの 17 行目を表示

このコードが実際に正規表現をコンパイルしており、regexp.MustCompile 関数を呼び出していることがわかります。

Go ソースコードの 17 行目が regexp.MustCompile を呼び出している

これはレポートに表示されていた CheckMessage 関数内にあることも確認できます。これで、この Go コードを最適化するのは簡単です!

Go ソースファイル内の CheckMessage 関数の定義

自動モニタリングとレポート

本番環境のワークロードに対しては、OpenResty XRay がプロセスを継続的にモニタリングし、Insights ページで日次および週次のレポートを自動生成します。手動でのガイド付き分析は不要です。

Go アプリケーション向けに Insights ページが自動生成した日次・週次の CPU レポート

よくある質問

Go プログラムの CPU 使用率が高いのはなぜですか?

Go の高 CPU 使用率のよくある原因は、ホットなコードパス内にコストの高い処理があることです。今回のケースでは、OpenResty XRay が CPU のボトルネックを正規表現のコンパイルに特定しました。標準 regexp ライブラリの関数が CPU 時間の 36.8% を占めており、これらは業務関数 CheckMessage から prev_processor.go の 17 行目で呼び出されていました。CPU フレームグラフは、業務ロジックからランタイムライブラリの関数までの完全な呼び出しチェーンを明らかにします。

Go で正規表現をコンパイルするのはコストが高いですか?

はい。正規表現のコンパイルはマッチング用のオートマトンを構築するため、コンパイル済みのパターンを実行するよりもはるかにコストがかかります。OpenResty XRay のレポートは regexp のコンパイル関数を明確にコストが高いものとして示し、ホットなコードパスでの呼び出しを避けるよう推奨しています。一般的なやり方は、各パターンを一度だけコンパイルしてその結果を再利用し、繰り返しコンパイルしないことです。

Go の高 CPU の原因となるコードを見つけるにはどうすればよいですか?

OpenResty XRay のガイド付き分析を使い、Go レベルの CPU フレームグラフを生成します。フレームグラフは関数呼び出しをスタックで表示し、ボックスの幅が CPU 時間を表します。関数のボックスにマウスカーソルを合わせるとソースファイルのパスと行番号が表示されるので、そのファイルを任意のエディタで開いて、原因となっている正確なコードを確認できます。計装もコードの変更も不要です。

OpenResty XRay について

OpenResty XRay動的トレーシング製品であり、実行中のアプリケーションを自動的に分析して、パフォーマンスの問題、動作の問題、セキュリティの脆弱性を解決し、実行可能な提案を提供いたします。基盤となる実装において、OpenResty XRay は弊社の Y 言語によって駆動され、Stap+、eBPF+、GDB、ODB など、様々な環境下で複数の異なるランタイムをサポートしております。

このチュートリアルがお役に立ちましたら、当ブログおよび YouTube チャンネル のご購読をお願いいたします。ありがとうございます!

著者について

章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。

章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しております。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」、「動的トレーシング」、「機械プログラミング」 の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っております。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立いたしました。同社の主力製品である OpenResty XRay動的トレーシング技術を利用した非侵入型の障害分析および排除ツール)と OpenResty Edge(マイクロサービスおよび分散トラフィックに最適化された多機能ゲートウェイソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ております。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJITGDBSystemTapLLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しております。

翻訳

英語版の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!