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

Function Compute:Tracing Analysis

最終更新日:Sep 02, 2024

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

背景

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などのサービスにアクセスするのにかかる時間を記録できます。

サンプルコード

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

OpenTelemetry用SDKの使用 (推奨)

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

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

  • pom.xmlファイルに依存関係を追加します。

      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>com.aliyun.fc.runtime</groupId>
          <artifactId>fc-java-core</artifactId>
          <version>1.4.1</version>
        </dependency>
        <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-api</artifactId>
          <version>1.19.0</version>
        </dependency>
        <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-sdk</artifactId>
          <version>1.19.0</version>
        </dependency>
        <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-semconv</artifactId>
          <version>1.19.0-alpha</version>
        </dependency>
        <dependency>
          <groupId>io.opentelemetry</groupId>
          <artifactId>opentelemetry-exporter-jaeger-thrift</artifactId>
          <version>1.19.0</version>
        </dependency>
        <dependency>
          <groupId>io.jaegertracing</groupId>
          <artifactId>jaeger-thrift</artifactId>
          <version>1.8.1</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-simple</artifactId>
          <version>1.6.6</version>
        </dependency>
      </dependencies>
  • データをTracing Analysisに報告します。

    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        String endpoint = context.getTracing().getJaegerEndpoint();
        try {
            ExampleConfiguration.initOpenTelemetry(endpoint);
        } catch (TTransportException e) {
            throw new RuntimeException(e);
        }
    
        SpanContext spanContext = contextFromString(context.getTracing().getSpanContext());
    
        startMySpan(io.opentelemetry.context.Context.current().with(Span.wrap(spanContext)));
    }
  • トレーサーへのアクセスを提供するグローバルOpenTelemetryオブジェクトを作成します。

    static OpenTelemetry initOpenTelemetry(String jaegerEndpoint) throws TTransportException {
        // Export traces to Jaeger.
        JaegerThriftSpanExporter jaegerExporter =
            JaegerThriftSpanExporter.builder()
            .setThriftSender(new Builder(jaegerEndpoint).build())
            .setEndpoint(jaegerEndpoint)
            .build();
    
        Resource serviceNameResource =
            Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "otel-jaeger-example"));
    
        // Specify a Jaeger exporter as the processor of the span.
        SdkTracerProvider tracerProvider =
            SdkTracerProvider.builder()
            .addSpanProcessor(SimpleSpanProcessor.create(jaegerExporter))
            .setResource(Resource.getDefault().merge(serviceNameResource))
            .build();
        OpenTelemetrySdk openTelemetry =
            OpenTelemetrySdk.builder().setTracerProvider(tracerProvider).buildAndRegisterGlobal();
    
        // Disable the SDK when the Java virtual machine (JVM) exits.
        Runtime.getRuntime().addShutdownHook(new Thread(tracerProvider::close));
    
        return openTelemetry;
    }
  • Contextのトレース情報を取得し、トレース情報をSpanContextに変換します。

    SpanContext contextFromString(String value) throws IOException {
        {
            if (value != null && !value.equals("")) {
                String[] parts = value.split(":");
                if (parts.length != 4) {
                    throw new RuntimeException(value);
                } else {
                    String traceId = parts[0];
                    if (traceId.length() <= 32 && traceId.length() >= 1) {
                        return SpanContext.createFromRemoteParent("0000000000000000"+parts[0], parts[1], TraceFlags.getSampled(), TraceState.getDefault());
                    } else {
                        throw new RuntimeException("Trace id [" + traceId + "] length is not withing 1 and 32");
                    }
                }
            } else {
                throw new RuntimeException();
            }
        }
    }
  • トレーサーを作成し、変換されたコンテキストを使用して子スパンを作成します。 スパンは、呼び出しトレースで名前が付けられ、時間が設定された継続的に実行可能なコードスニペットを表します。 スパンに基づいて子スパンを作成することもできます。

    void startMySpan(io.opentelemetry.context.Context ctx){
        Tracer tracer = GlobalOpenTelemetry.getTracer("fc-Trace");
        Span parentSpan = tracer.spanBuilder("fc-operation").setParent(ctx).startSpan();
        parentSpan.setAttribute("version","fc-v1");
        try {
            TimeUnit.MILLISECONDS.sleep(150);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        child(parentSpan.storeInContext(ctx));
        parentSpan.end();
    }
    
    void child(io.opentelemetry.context.Context ctx){
        Tracer tracer = GlobalOpenTelemetry.getTracer("fc-Trace");
        Span childSpan = tracer.spanBuilder("fc-operation-child").setParent(ctx).startSpan();
        childSpan.addEvent("timeout");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        childSpan.end();
    }

JaegerのSDKを使用する

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

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

  • pom.xmlファイルに依存関係を追加します。

    <dependencies>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
      </dependency>
      <dependency>
        <groupId>com.aliyun.fc.runtime</groupId>
        <artifactId>fc-java-core</artifactId>
        <version>1.4.1</version>
      </dependency>
      <dependency>
        <groupId>io.jaegertracing</groupId>
        <artifactId>jaeger-client</artifactId>
        <version>1.8.1</version>
      </dependency>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.6.6</version>
      </dependency>
    </dependencies>
  • データをTracing Analysisに報告します。

    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
    
        registerTracer(context);
    
        JaegerSpanContext spanContext = contextFromString(context.getTracing().getSpanContext());
    
        startMySpan(spanContext);
    }
  • コンテキストのトレース情報に基づいて、トレーサーオブジェクトを作成します。

    void registerTracer(Context context){
        io.jaegertracing.Configuration config = new io.jaegertracing.Configuration("FCTracer");
        io.jaegertracing.Configuration.SenderConfiguration sender = new io.jaegertracing.Configuration.SenderConfiguration();
        sender.withEndpoint(context.getTracing().getJaegerEndpoint());
        config.withSampler(new io.jaegertracing.Configuration.SamplerConfiguration().withType("const").withParam(1));
        config.withReporter(new io.jaegertracing.Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));
        GlobalTracer.register(config.getTracer());
    }
  • SpanContextを変換し、カスタムスパンを作成します。 スパンに基づいて子スパンを作成することもできます。

    static JaegerSpanContext contextFromString(String value) throws MalformedTracerStateStringException, EmptyTracerStateStringException {
        if (value != null && !value.equals("")) {
            String[] parts = value.split(":");
            if (parts.length != 4) {
                throw new MalformedTracerStateStringException(value);
            } else {
                String traceId = parts[0];
                if (traceId.length() <= 32 && traceId.length() >= 1) {
                    return new JaegerSpanContext(0L, (new BigInteger(traceId, 16)).longValue(), (new BigInteger(parts[1], 16)).longValue(), (new BigInteger(parts[2], 16)).longValue(), (new BigInteger(parts[3], 16)).byteValue());
                } else {
                    throw new TraceIdOutOfBoundException("Trace id [" + traceId + "] length is not withing 1 and 32");
                }
            }
        } else {
            throw new EmptyTracerStateStringException();
        }
    }