すべてのプロダクト
Search
ドキュメントセンター

Function Compute:Tracing Analysis

最終更新日:Sep 02, 2024

このトピックでは、Goランタイム環境でのトレース分析機能について説明します。

背景

Alibaba Cloud Tracing AnalysisはOpenTracing標準を採用しており、オープンソースコミュニティと互換性があります。 Tracing Analysisは、分散アプリケーションの開発者にさまざまな機能を提供します。 たとえば、開発者は分散トレースのクエリと診断、分散トポロジの動的な検出、アプリケーションのパフォーマンスのリアルタイムな要約を行うことができます。

Function ComputeはTracing Analysisと統合します。 Jaeger SDKまたはOpenTelemetryを使用してトレース情報をアップロードし、関数の呼び出しを追跡できます。 Tracing Analysisは、サーバーレスアーキテクチャのパフォーマンスボトルネックの分析と診断に役立ちます。 これにより、サーバーレスシナリオでの開発と診断の効率が向上します。

概要

Tracing Analysisは、Function Computeコンソールで設定できます。 詳細については、「トレース分析の有効化」をご参照ください。

サービスのTracing Analysisを有効にすると、Function Computeはシステムで消費された時間を自動的に記録します。 時間は、コールドスタート時間、イニシャライザ関数の実行時間、及び関数の実行時間を含む。 次の図のシステムスパンの詳細については、「スパン名の説明」をご参照ください。 Tracing Analysis

ビジネス側の関数で消費された時間を記録できます。 たとえば、[カスタムスパンの作成] を使用して、関数内でApsaraDB RDSやApsara File Storage NASなどのサービスにアクセスするのにかかる時間を記録できます。

サンプルコード

Goランタイム環境でのFunction Computeのトレース分析では、OpenTracing仕様のJaeger実装に基づいて、次の方法を使用してカスタムスパンを作成できます。

OpenTelemetry用SDKの使用 (推奨)

Goコードでは、SDK for OpenTelemetryを使用してコードのインストルメンテーションを実行し、データをTracing Analysisに報告できます。 完全なサンプルコードについては、「golang-tracing-openTelemetry」をご参照ください。

サンプルコードの詳細を次に示します。

  • 依存関係を追加します。

    go get github.com/aliyun/fc-runtime-go-sdk
    go get go get go.opentelemetry.io/otel
    go get go.opentelemetry.io/otel/sdk
    go get go.opentelemetry.io/otel/exporters/jaeger
  • データをTracing Analysisに報告します。

    func HandleRequest(ctx context.Context, event MyEvent) (string, error) {
        // Obtain the tracing information of the context in Function Compute.
        fctx, ok := fccontext.FromContext(ctx)
        if !ok {
            return "", fmt.Errorf("failed to get FcContext")
        }
        spanCtx, endpoint, err := getFcTracingInfo(fctx)
        if err != nil {
            return "", fmt.Errorf("failed to getFcTracingInfo, error: %v", err)
        }
        // Create a tracer provider.
        tp, err := NewTracerProvider(endpoint)
        if err != nil {
            return "", fmt.Errorf("OpenTracingJaegerEndpoint: %s, error: %v", fctx.Tracing.JaegerEndpoint, err)
        }
        // Set the tracer provider to a global tracer provider.
        otel.SetTracerProvider(tp)
        if err != nil {
            return "", fmt.Errorf("failed to getFcSpanCtx, error: %v", err)
        }
        // Create a custom span.
        startMySpan(trace.ContextWithSpanContext(ctx, spanCtx))
        return fmt.Sprintf("hello world! Hello, %s! ", event.Name), nil
    }
  • トレーサーへのアクセスを提供するトレーサープロバイダーを作成します。

    func tracerProvider(url string) (*tracesdk.TracerProvider, error) {
        // Create a Jaeger exporter.
        exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
        if err != nil {
            return nil, err
        }
        tp := tracesdk.NewTracerProvider(
            // Register an exporter.
            tracesdk.WithBatcher(exp),
            // Record the application information in the resource.
            tracesdk.WithResource(resource.NewWithAttributes(
                semconv.SchemaURL,
                semconv.ServiceNameKey.String("FCTracer"),
                attribute.String("environment", "production"),
                attribute.Int64("ID", 1),
            )),
        )
        return tp, nil
    }
  • Contextのトレース情報を取得し、OpenTracing SpanContextをOpenTelemetry SpanContextに変換します。

    func getFcTracingInfo(fctx *fccontext.FcContext) (trace.SpanContext, string, error) {
        // Obtain the tracing information.
        spanContext := trace.SpanContext{}
        endpoint := fctx.Tracing.JaegerEndpoint
        OpenTracingSpanContext := fctx.Tracing.OpenTracingSpanContext
        if len(endpoint) == 0 {
            return spanContext, endpoint, fmt.Errorf("invalid jaeger endpoint")
        }
        spanContextSlice := strings.Split(OpenTracingSpanContext, ":")
    
        // Pad zeros in front of the trace ID.
        tid, err := trace.TraceIDFromHex("0000000000000000" + spanContextSlice[0])
        if err != nil {
            return spanContext, endpoint, err
        }
        fid := trace.FlagsSampled
        spanContext = spanContext.WithTraceID(tid).WithTraceFlags(fid).WithRemote(true)
        return spanContext, endpoint, nil
    }
  • トレーサーを作成し、変換されたOpenTelemetry SpanContextを使用して子スパンを作成します。 スパンは、呼び出しトレースで名前が付けられ、時間が設定された継続的に実行可能なコードスニペットを表します。 スパンに基づいて子スパンを作成することもできます。

    func startMySpan(ctx context.Context) {
        // Use a global tracer provider.
        tr := otel.Tracer("fc-Trace")
        ctx, parentSpan := tr.Start(ctx, "fc-operation")
        defer parentSpan.End()
        parentSpan.SetAttributes(attribute.Key("version").String("fc-v1"))
        time.Sleep(150 * time.Millisecond)
        child(ctx)
    }
    
    func child(ctx context.Context) {
        tr := otel.Tracer("fc-Trace")
        _, childSpan := tr.Start(ctx, "fc-operation-child")
        defer childSpan.End()
        time.Sleep(100 * time.Millisecond)
        childSpan.AddEvent("timeout")
    }

JaegerのSDKを使用する

JaegerのSDKを使用して、コードのインストルメンテーションを実行し、データをTracing Analysisに報告できます。 完全なサンプルコードについては、「golang-tracing」をご参照ください。

サンプルコードの詳細を次に示します。

  • 依存関係を追加します。

    go get github.com/aliyun/fc-runtime-go-sdk
    go get github.com/opentracing/opentracing-go
    go get github.com/uber/jaeger-client-go
  • データをTracing Analysisに報告します。

    func HandleRequest(ctx context.Context, event MyEvent) (string, error) {
        // Obtain the tracing information of the context in Function Compute.
        fctx, _ := fccontext.FromContext(ctx)
        endpoint := fctx.Tracing.JaegerEndpoint
        OpenTracingSpanContext := fctx.Tracing.OpenTracingSpanContext
        if len(endpoint) == 0 {
            return "", fmt.Errorf("invalid jaeger endpoint")
        }
        // Create a tracer.
        tracer, closer := NewJaegerTracer("FCTracer", endpoint)
        defer closer.Close()
        // Restore the SpanContext.
        spanContext, err := jaeger.ContextFromString(OpenTracingSpanContext)
        if err != nil {
            return "", fmt.Errorf("OpenTracingSpanContext: %s, error: %v", fctx.Tracing.OpenTracingSpanContext, err)
        }
        // Create a custom span.
        startMySpan(spanContext, tracer)
        return fmt.Sprintf("hello world! Hello, %s! ", event.Name), nil
    }
  • トレーサーへのアクセスを提供するトレーサーオブジェクトを作成します。

    func NewJaegerTracer(service, endpoint string) (opentracing.Tracer, io.Closer) {
        sender := transport.NewHTTPTransport(endpoint)
        tracer, closer := jaeger.NewTracer(service,
            jaeger.NewConstSampler(true),
            jaeger.NewRemoteReporter(sender))
        return tracer, closer
    }
  • SpanContextを変換し、カスタムスパンを作成します。 スパンに基づいて子スパンを作成することもできます。

    func startMySpan(context jaeger.SpanContext, tracer opentracing.Tracer) {
        parentSpan := tracer.StartSpan("MyFCSpan", opentracing.ChildOf(context))
        defer parentSpan.Finish()
        parentSpan.SetOperationName("fc-operation")
        parentSpan.SetTag("version", "fc-v1")
        time.Sleep(150 * time.Millisecond)
        // Enable a child span.
        childSpan := tracer.StartSpan("fc-operation-child", opentracing.ChildOf(parentSpan.Context()))
        defer childSpan.Finish()
        time.Sleep(100 * time.Millisecond)
        childSpan.LogFields(
            log.String("type", "cache timeout"),
            log.Int("waited.millis", 100))
    }