Go アプリケーションのプロファイリング

このページでは、プロファイリング データを収集し、そのデータを Google Cloud プロジェクトに送信するように Go アプリケーションを変更する方法について説明します。プロファイリングの全般的な情報については、プロファイリングのコンセプトをご覧ください。

Go のプロファイル タイプ:

  • CPU 時間
  • ヒープ
  • 割り当てられたヒープ
  • 競合(Go Mutex)
  • スレッド(Go Goroutine)

サポートされている Go 言語バージョン:

  • 特に明記されていない限り、正式に管理されているすべての Go リリース。詳細については、Go 言語のリリース ポリシーをご覧ください。

サポートされているプロファイリング エージェントのバージョン:

  • エージェントの最新リリースがサポートされています。一般に、1 年以上前のリリースはサポートされません。エージェントの最新リリース バージョンを使用することをおすすめします。

サポートされているオペレーティング システム:

  • Linux。Go アプリケーションのプロファイリングは、標準 C ライブラリが glibc または musl で実装されている Linux カーネルでサポートされています。Linux Alpine カーネルに固有の構成情報については、Linux Alpine で実行するをご覧ください。

サポートされる環境:

Profiler API を有効にする

プロファイリング エージェントを使用する前に、基盤となる Profiler API が有効になっている必要があります。Cloud SDK gcloud コマンドライン ツールまたは Cloud Console で API のステータスを確認し、無効になっている場合は有効にしてください。

Cloud SDK

  1. ワークステーションに Cloud SDK がまだインストールされていない場合は、Google Cloud SDK をご覧ください。

  2. 次のコマンドを実行します。

    gcloud services enable cloudprofiler.googleapis.com
    

詳細については、gcloud services をご覧ください。

Cloud Console

  1. [API とサービス] ダッシュボードに移動します。

    [API とサービス] に移動

  2. API へのアクセスで使用するプロジェクトを選択します。

  3. [API とサービスを有効化] ボタンをクリックします。

    API とサービスの追加

  4. Profiler API を検索します。

  5. 検索結果で、[Cloud Profiler API] を選択します。

    [Cloud Profiler API] が表示されない場合は、[Stackdriver Profiler API] を選択します。

  6. [API が有効です] が表示されている場合、API はすでに有効になっています。そうでない場合は、[有効にする] ボタンをクリックします。

Cloud Profiler の使用

サポートされているすべての環境で Profiler を使用するには、アプリケーションにパッケージをインポートし、アプリケーションの早い段階で Profiler を初期化します。

MutexProfiling 構成オプションを true に設定すると、ミューテックス競合プロファイリング(インターフェースでは「競合」)を有効にできます。

構成オプションを含む Profiler API の詳細については、公開 API のドキュメントをご覧ください。

Compute Engine

Compute Engine の場合、profiler.ConfigService にプロファイリング対象のサービスの名前を設定し、必要に応じて ServiceVersion にサービスのバージョンを設定します。


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

ソースコードの依存関係を手動で取得する場合は、ビルド スクリプトまたは Dockerfile に以下を追加する必要があります。

go get -u cloud.google.com/go/profiler

GKE

GKE の場合、profiler.ConfigService にプロファイリング対象の Service の名前を設定し、必要に応じて ServiceVersion に Service のバージョンを設定します。


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

ソースコードの依存関係を手動で取得する場合は、ビルド スクリプトまたは Dockerfile に以下を追加する必要があります。

go get -u cloud.google.com/go/profiler

App Engine

App Engine フレキシブル環境と App Engine スタンダード環境の場合、コードの追加は Compute Engine と GKE の場合とほぼ同じです。例外が 1 つあります。App Engine 環境では、Service パラメータと ServiceVersion パラメータは環境から取得されるため、これらを指定する必要はありません。


// appengine is an example of starting cloud.google.com/go/profiler on
// App Engine.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(profiler.Config{
		// Service and ServiceVersion can be automatically inferred when running
		// on App Engine.
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",
	}); err != nil {
		// TODO: Handle error.
	}
}

アプリケーションをローカルで実行する場合は、ProjectID(Google Cloud プロジェクトの ID)と Service パラメータを profiler.Config に設定します。これらのパラメータは、ローカル環境から取得されません。ServiceVersion を設定する必要はありません。

App Engine スタンダード環境の場合は、Go 1.11 へのアプリの移行で、アプリケーションに必要な変更の詳細を確認してください。また、Cloud SDK バージョン 226.0.0 以降を使用する必要があります。Cloud SDK をアップデートするには、次のコマンドを実行します。

    gcloud components update

アプリケーションを実行するには:

  1. 依存関係を更新します。

    go get -u cloud.google.com/go/profiler
    
  2. App Engine フレキシブル環境または App Engine スタンダード環境にアプリケーションをデプロイします。

    gcloud app deploy [DEPLOYMENT]
    

    DEPLOYMENT は構成ファイルのパスです。たとえば、DEPLOYMENTmain/app.yaml になります。

データを分析する

Profiler が収集したデータを Profiler のインターフェースに表示し、分析できます。このインターフェースの開始方法については、Profiler インターフェースを開くをご覧ください。

サービス名とバージョンの引数

Profiler エージェントを読み込むときに、service-name 引数とオプションの service-version 引数を指定して構成します。

Profiler は、サービス名で指定されたサービスのすべてのレプリカからプロファイリング データを収集します。Profiler サービスは、サービス バージョンとゾーンの組み合わせに対して、1 つのサービス名について平均で 1 分あたり 1 個のプロファイルを作成します。

たとえば、1 つのサービスの 2 つのバージョンが 3 つのゾーンのレプリカで実行されている場合、Profiler はそのサービスについて 1 分あたり平均で 6 個のプロファイルを作成します。

レプリカで異なるサービス名を使用している場合、サービスが必要以上にプロファイリングされるため、オーバーヘッドが大きくなります。

サービス名を選択する場合は、次の点に注意してください。

  • アプリケーション アーキテクチャでサービスを明確に識別できる名前を選択してください。1 つのサービスまたはアプリケーションしか実行していない場合、どのようなサービス名を選択するかはさほど問題になりません。しかし、アプリケーションが一連のマイクロサービスとして実行されている場合は、名前の選択が重要になります。

  • service-name 文字列で、プロセス ID などのプロセス固有の値を使用しないでください。

  • service-name 文字列は次の正規表現と一致する必要があります。

    ^[a-z]([-a-z0-9_.]{0,253}[a-z0-9])?$

サービス名として imageproc-service のような静的な文字列を使用することをおすすめします。

サービス バージョンは省略可能です。サービス バージョンを指定すると、複数のインスタンスからプロファイリング情報が集約され、バージョンごとに表示されます。これは、複数のバージョンがデプロイされているときの識別に役立ちます。Profiler UI では、データをサービス バージョンでフィルタできます。これにより、コードの新旧バージョンのパフォーマンスを比較できます。

service-version 引数には、自由形式の文字列を指定できますが、通常は、バージョン番号のような値を使用します(例: 1.0.02.1.2)。

エージェント ロギング

プロファイリング エージェントには、ログにデバッグ情報を出力する機能があります。デフォルトでは、エージェント ロギングは無効になっています。

エージェント ロギングを有効にするには、エージェントの起動時に DebugLogging オプションを true に設定します。

profiler.Start(profiler.Config{..., DebugLogging: true});

トラブルシューティング

このセクションでは、Go アプリケーションのプロファイリングに固有の問題について説明します。一般的な問題のヘルプについては、こちらのトラブルシューティングをご覧ください。

動作 原因 解決策
-buildmode=c-archive を使用してビルドされたアプリケーションでは、CPU 時間プロファイルは収集されません。ヒープ、競合、スレッドのプロファイルが収集されます。 GitHub の問題 デフォルトでは、-buildmode フラグが c-archive または c-shared の場合、Go アプリケーションに対して CPU プロファイリングが有効になっていません。 profiler.Start を呼び出す前に
signal.Notify(make(
chan os.Signal), syscall.SIGPROF)
への呼び出しを追加します。
GitHub の問題へのレスポンス

Linux Alpine で実行する

Linux Alpine 用の Go プロファイリング エージェントは、Google Kubernetes Engine の構成でのみサポートされています。

Linux Alpine で Docker イメージ(golang:alpinealpine など)を使用すると、次の認証エラーが表示されることがあります。

connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"

エラーの詳細を確認するには、エージェント ロギングを有効にする必要があります。 デフォルトでは、Go エージェントはログメッセージを出力しません。

上記のエラーは、Linux Alpine の Docker イメージに、デフォルトでインストールされているはずのルート SSL 証明書がないことを示しています。これらの証明書は、プロファイリング エージェントが Profiler API と通信するために必要になります。このエラーを解決するには、次の apk コマンドを Dockerfile に追加します。

FROM alpine
...
RUN apk add --no-cache ca-certificates

その後、アプリケーションを再度ビルドし、デプロイする必要があります。

次のステップ

Cloud Profiler インターフェースの使用で Profiler のグラフとコントロールについて学習します。詳細については、以下をご覧ください。