LoginSignup
1
0

More than 3 years have passed since last update.

openTelemetryでGCPのtraceを使う方法

Posted at

本記事ではopenTelemetryというオープンソースを利用して、GoogleCloudPlatform(GCP)のTrace機能で計測をする方法を記載します。今回のTrace対象はCloudRun上で実行します。

openTelemetryとは

openTelemetryは、複雑化していくシステムの動作を分析するためのオープンソースです。実行された処理の時間計測をおこなう事で、ボトルネックや障害に繋がる原因を探す事ができます。openCensusという分散トレーシングのオープンソースがあり、openTelemetryはその後継になります。
openTelemetry

Traceの構造

Traceを始める時に、まずはTraceIDという識別用のIDを作成します。このIDによりTraceの対象を一意にしたりSpanという計測区間との紐付けを行います。Spanは親子関係を持ち、計測の細分化をする事が出来ます。下の図は、1番上の親Spanを3分割して中央の子Span2をさらに詳細にトレースする構造になっています。

image.png

Goを使って実装

端末 : MacBook PRO
Go : go1.15.2
クラウド : GCP

インストール

  1. goをダウンロード
    https://golang.org/doc/install
  2. ダウンロードしたファイルからインストール
  3. PATHを設定を追加
$ export PATH=/usr/local/go/bin:$PATH

初期化

go modを使ってモジュールの管理をしていくため、初期化を行います。
以下のコマンドを実行するとgo.modというファイル作成されます。

$ go mod init example.com/trace

あとはコード内に読み込むモジュールの設定をしてビルドをする事で、自動でgo.modに読み込むモジュールの設定を追記してくれます。

構成

最終的な構成は以下のようになります。

.
├── Dockerfile
├── go.mod
├── go.sum
└── main.go

ソースコード

main.go

HTTPのリクエストを受けるAPIを作成しています。
トレースをするためのパッケージを読み込み、プロジェクトの設定などの初期設定を行います。
このコードでは、
1. example.com/traceというTracerを作成
2. sampleという名前のspanを開始
3. 各stepでの処理時間を計測
をしています。


package main

import (
        "context"
        "fmt"
        "log"
        "net/http"
        "os"
        "time"

        texporter "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace"
        "go.opentelemetry.io/otel/api/global"
        sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

func handler(w http.ResponseWriter, r *http.Request) {

        exporter, err := texporter.NewExporter(texporter.WithProjectID("{project id}"))
        if err != nil {
                log.Fatalf("texporter.NewExporter: %v", err)
        }

        tp, err := sdktrace.NewProvider(sdktrace.WithSyncer(exporter))
        if err != nil {
                log.Fatal(err)
        }

        global.SetTraceProvider(tp)
        tracer := global.TraceProvider().Tracer("example.com/trace")

        ctx, span := tracer.Start(context.Background(), "sample")
        defer span.End()

        _, step1 := tracer.Start(ctx, "step1")
        time.Sleep(time.Second * 1)
        step1.End()

        _, step2 := tracer.Start(ctx, "step2")
        time.Sleep(time.Second * 2)
        step2.End()

        fmt.Fprintf(w, "Done\n")
}

func main() {

        http.HandleFunc("/", handler)

        port := os.Getenv("PORT")
        if port == "" {
                port = "8080"
        }

        log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
}

Dockerfile

マルチステージビルドを用いて、上部で実行ファイルの作成を行います。作成した実行ファイルをのみをalpineのイメージにコピーして、デプロイするイメージを作成します。


FROM golang:1.15 as builder

WORKDIR /app

COPY go.* ./
RUN go mod download
COPY . ./

RUN CGO_ENABLED=0 GOOS=linux go build -v -o server


FROM alpine:3
RUN apk add --no-cache ca-certificates

COPY --from=builder /app/server /server

CMD ["/server"]

構築

Cloud Run上にデプロイを行います。
gcloud builds submitで、イメージのビルドを行いContainer Registryに保存します。そのあと、gcloud run deployを使用して、保存したイメージからデプロイをします。


$ gcloud builds submit --tag gcr.io/$1/{イメージ名}
$ gcloud run deploy {サービス名} --image gcr.io/$1/{イメージ名} --platform managed --memory 256M --region {region} --allow-unauthenticated

結果

デプロイしたAPIを実行してGCPのTraceを見ると、以下のように表示されます。
スクリーンショット 2020-09-23 19.02.43.png

sampleのspanの中にstep1とstep2の実行時間が可視化されて表示されます。
トレーサを作成して、計測したい部分を囲む事で簡単に時間の計測をする事が出来ました。また、コンテキスト引数にトレーサを実行する事で入れ子で計測する事が出来るので、APIの中でもどの部分に処理の時間がかかっているか調べる事が出来ます。トレースの結果を集める事で恒常的に速度が遅いのかその時だけ処理が遅くなったかも後から検証する事が出来たりと、メリットは大きいと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0