OTEP-0182: OTLPにおけるSpanContext.IsRemoteのエクスポート

スパンの親がリモートかどうかを示すよう、OTLPを更新します。

動機

エントリーポイントのスパン、すなわち親を持たないスパン(トレースのルート)、またはリモート親を持つスパンのみを後処理したり可視化したりすることが有用な場合があります。 たとえば、Elastic APMのソリューションはエントリーポイントのスパンをハイライトし(Elastic APMはこれらを「トランザクション」と呼びます)、これらをユーザーインターフェース上のトップレベルの操作として表示します。

目標は、完全な分散トレースをDAG(有向非巡回グラフ)として組み立てることなく、サービスに入ってくる、あるいはサービス内で発生したリクエストを表すスパンを識別することです。 トレースのルートを識別することは容易ですが、リモート親を持つスパンを識別することはできません。

以下は、エントリーポイントのスパンに枠線を付けた、作為的な分散トレースの例です。

graph TD
    subgraph comments_service
    POST_comments(POST /comment)
    POST_comments --> comments_send(comments send)
    end

    subgraph auth_service
    POST_comments --> POST_auth(POST /auth)
    POST_auth --> LDAP
    end

    subgraph user_details_service
    POST_comments --> GET_user_details(GET /user_details)
    GET_user_details --> SELECT_users(SELECT FROM users)
    end

    subgraph comments_inserter
    comments_send --> comments_receive(comments receive)
    comments_receive --> comments_process(comments process)
    comments_process --> INSERT_comments(INSERT INTO comments)
    end

    style POST_comments stroke-width:4
    style POST_auth stroke-width:4
    style GET_user_details stroke-width:4
    style comments_receive stroke-width:4

解説

スパンのOTLPエンコーディングには、スパンの親がリモートかどうかを識別するためのブール値の parent_span_is_remote フィールドがあります。 すべてのOpenTelemetry SDKがこのフィールドを設定し、バックエンドはこれを使ってスパンをエントリーポイントのスパンとして識別できます。 スパンは、親を持たない場合(parent_span_id が空の場合)、または parent_span_is_remote が真である場合に、エントリーポイントのスパンとみなすことができます。

内部の詳細

最初の部分は、トレースのprotobufを更新し、Span メッセージboolean parent_span_is_remote フィールドを追加することです。

SpanContext.IsRemoteは、スパンコンテキストがリモート親から伝播されたかどうかを識別します。 各SDKのOTLPエクスポーターは、これを新しい parent_span_is_remote フィールドに記録するように更新される必要があります。

古いOTLPバージョンとの後方互換性のため、protobufフィールドは nullabletruefalse、または未指定)でなければならず、opentelemetry-collectorのprotogenコードは、バックエンドのエクスポーターがこのフィールドが設定されているかどうかを識別できるAPIを提供する必要があります。

package pdata

// ParentSpanIsRemote indicates whether ms's parent span is remote, if known.
// If the parent span remoteness property is known then the "ok" result will be true,
// and false otherwise.
func (ms Span) ParentSpanIsRemote() (remote bool, ok bool)

トレードオフと緩和策

特に識別されていません。

先行技術と代替技術

代替案1: 他のスパンにエントリーポイントのスパンIDを含める

親スパンがリモートかどうかを識別する代わりに、すべての非エントリーポイントのスパンにエントリーポイントのスパンのIDをエンコードして伝播するという方法も考えられます。 これにより、このフィールドがないことでエントリーポイントのスパンを識別できます。

エントリーポイントのスパンIDは、リモート親を持つスパンを開始するときに取得され、SpanContext を通じて伝播されます。 Span のprotobufメッセージ定義に新しい entry_span_id フィールドを導入し、OTLPエクスポーターでこれを設定します。

これはもともとOpenCensusで提案されましたが、決着はついていません。

この代替案の欠点は次のとおりです。

  • SpanContext を拡張してエントリーポイントのスパンIDを含める必要があり、SDKはこれを取得・伝播するように更新される必要があります
  • 追加のprotobufフィールドは、ブール値フィールドの1バイトに対して、追加で8バイトになります

このアプローチの主な利点は、バックエンドがプロセスのサブグラフによってスパンをグループ化できるようになることです。

代替案2: エントリーポイントのスパンを識別するためのセマンティック規約の属性を導入する

スパンに新しいフィールドを追加する代わりに、エントリーポイントのスパンのみに新しいセマンティック規約の属性を追加するという方法も考えられます。

このアプローチはすべてのスパンのメモリフットプリントの増加を避けられますが、エントリーポイントのスパンについてはより大きなメモリフットプリントになります。 したがって、このアプローチの利点は、エントリーポイントのスパンと内部スパンの比率に依存し、場合によってはむしろコストが高くなる可能性もあります。

代替案3: SpanKindの値を拡張する

もう一つの代替案は、SpanKindの値を拡張して、CONSUMERスパンがリモート親を持つかローカル親を持つかを曖昧さなく定義することです(たとえば、メッセージのポーリングのユースケースで)。

たとえば、SpanKindのRemote-Incomingプロパティに対して明確に「いいえ」となる新しいSpanKind(たとえば AMBIENT_CONSUMER)を導入し、REMOTE_CONSUMER はSpanKindのRemote-Incomingプロパティに対して明確に「はい」となるようにします。 このアプローチの欠点は、CONSUMER スパンのセマンティクスに対する破壊的変更になることです。

未解決の問題

parent_span_is_remoteSpanKind の関係

SpanKind の仕様は次のように説明しています。

The first property described by SpanKind reflects whether the Span is a "logical" remote child or parent ...

しかし、仕様は CONSUMER スパンの種類に関して、この「論理的な」リモート親のプロパティについて曖昧なままです。 それにもかかわらず、提案されているフィールド parent_span_is_remote は、その SpanKind のプロパティといくらか重複しています。 仕様は SpanKind とその parent_span_is_remote との関係について、いくらかの明確化が必要になるでしょう。

今後の課題

他に識別されている今後の変更はありません。