Slide 1

Slide 1 text

非同期処理でも 分散トレーシングしたい! - OpenTelemetry × Pub/Sub - Jagu’e’r オブザーバビリティ分科会 Meetup#2 - Tomonori Hayashi 1

Slide 2

Slide 2 text

Tomonori Hayashi ● NTT コミュニケーションズ ○ ソフトウェアエンジニア ■ Front:TypeScript - React/Next.js ■ Infra:Google Cloud ● Google Cloud Partner Top Engineer 2024 - 2025 ● Google Cloud Tech Blog Challenge 2024 個人カテゴリ受賞 ● Google Cloud All Certifications ● 社外コミュニティ ○ Jagu’e’r (Google Cloud 公式ユーザーコミュニティ) ■ エバンジェリスト ■ オブザーバビリティ分科会 運営 2 @pHaya72 @t_hayashi

Slide 3

Slide 3 text

本日お話しすること ● インフラレベルの非同期処理のつらみ ● Pub/Sub をメッセージキューとして採用した場合の OpenTelemetry の絡み

Slide 4

Slide 4 text

4 非同期処理と言っても・・ 大きく二つに大別できそう アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージキューサービスを挟んで重い処理などを専用のサービス に任せて非同期に処理する

Slide 5

Slide 5 text

5 今回はインフラレベルの話 大きく二つに大別できそう アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージキューサービスを挟んで重い処理などを専用のサービス に任せて非同期に処理する

Slide 6

Slide 6 text

6 インフラレベルの非同期処理のつらみ 処理が分断されることで調査箇所が増える アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージキューサービスを挟んで重い処理などを専用のサービス に任せて非同期に処理する Service B の処理が失敗した場合 Service B のアプリケーションがバグる Service B のホストがバグる → Service B 内の話だから追跡しやすい

Slide 7

Slide 7 text

7 インフラレベルの非同期処理のつらみ 処理が分断されることで調査箇所が増える アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージサービスを挟んで重い処理などを専用のサービスに任せ て非同期に処理する Service B の処理が失敗した場合 Service B のアプリケーションがバグる Service B のホストがバグる → Service B 内の話だから追跡しやすい Service B の入力がバグる → なぜこのようにバグったか追跡しづらい

Slide 8

Slide 8 text

8 インフラレベルの非同期処理のつらみ 処理が分断されることで調査箇所が増える アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージサービスを挟んで重い処理などを専用のサービスに任せ て非同期に処理する Service B の処理が失敗した場合 Service B のアプリケーションがバグる Service B のホストがバグる → Service B 内の話だから追跡しやすい Service B の入力がバグる → なぜこのようにバグったか追跡しづらい 入力は Service A が送出しているから!

Slide 9

Slide 9 text

9 インフラレベルの非同期処理のつらみ 処理が分断されることで調査箇所が増える アプリケーションレベル インフラレベル Ex. 重い処理などでメインスレッドのブロッキングを防ぐためにバックグ ラウンドスレッドで非同期に処理する Ex. メッセージサービスを挟んで重い処理などを専用のサービスに任せ て非同期に処理する Service B の処理が失敗した場合 Service B のアプリケーションがバグる Service B のホストがバグる → Service B 内の話だから追跡しやすい Service B の入力がバグる → なぜこのようにバグったか追跡しづらい 入力は Service A が送出しているから! (もしかしたらメッセージキューもバグるかも)

Slide 10

Slide 10 text

10 一連のトレースになっていると嬉しい、けど・・ コンテキストの欠如 いわずもがなですが、コンテキストが伝播することで 分散トレーシングが可能となる Service A と Service B では PubSub などの メッセージキューを介することでコンテキストが 伝播せずに損失してしまう・・・ コンテキスト伝播の流れ これをどうにか解決したい!

Slide 11

Slide 11 text

11 直感的に思いつくのは・・ メッセージにコンテキストを含める Service A がパブリッシュするメッセージに コンテキストを含める Service B がサブスクライブしてメッセージに含まれる コンテキストを利用して生成したスパンを紐づける オブザーバビリティツール上で非同期処理でも 一連のトレースとして観測することできる! コンテキスト伝播の流れ 受け渡すメッセージに コンテキストを含める もっとスマートに解決したい!

Slide 12

Slide 12 text

12 Pub/Sub には Otel オプションが存在する Client が自動でコンテキストを伝播させる パブリッシャー/サブスクライバーそれぞれで実装する Pub/Sub Client でオプションを有効化する コンテキスト伝播の流れ Pub/Sub サブスクライバーでの実装 パブリッシャーでの実装

Slide 13

Slide 13 text

13 Pub/Sub には Otel オプションが存在する Client が自動でコンテキストを伝播させる パブリッシャー/サブスクライバーそれぞれで実装する Pub/Sub Client でオプションを有効化する コンテキスト伝播の流れ 受け渡すメッセージに コンテキストを含める サブスクライバーでの実装 パブリッシャーでの実装 Pub/Sub が受け取るメッセージ Pub/Sub

Slide 14

Slide 14 text

14 Pub/Sub には Otel オプションが存在する Client が自動でコンテキストを伝播させる パブリッシャー/サブスクライバーそれぞれで実装する Pub/Sub Client でオプションを有効化する サブスクライバーでの実装 パブリッシャーでの実装 ServiceA ServiceB ServiceA Pub/Sub Client

Slide 15

Slide 15 text

15 せっかくなのでコードを見てみる Pub/Sub Client のコード パブリッシャーが publish するタイミングで _open_telemetry_enabled が True だと start_create_span 関数や start_publisher_flow_control_span 関数が 実行される 引用:https://github.com/googleapis/python-pubsub/blob/main/google/cloud/pubsub_v1/publisher/client.py

Slide 16

Slide 16 text

せっかくなのでコードを見てみる Pub/Sub Client のコード start_create_spant 関数 Tracer を取得してスパンを生成 ・ユーザーがパブリッシュした _message.data ・ attributes には色々含まれている Event のスパンへの紐付け TraceContextTextMapPropagator で伝播 ・Pub/Sub に送られるメッセージの attributes key の googleclient_traceparent を つっこんでいる 引用:https://github.com/googleapis/python-pubsub/blob/main/google/cloud/pubsub_v1/open_telemetry/publish_message_wrapper.py どうやって伝播している?

Slide 17

Slide 17 text

17 【再掲】Pub/Sub には Otel オプションが存在する Client が自動でコンテキストを伝播させる パブリッシャー/サブスクライバーそれぞれで実装する Pub/Sub Client でオプションを有効化する コンテキスト伝播の流れ 受け渡すメッセージに コンテキストを含める サブスクライバーでの実装 パブリッシャーでの実装 Pub/Sub が受け取るメッセージ Pub/Sub

Slide 18

Slide 18 text

せっかくなのでコードを見てみる OpenTelemetry-Python のコード TextMapPropagator クラス サービス間でトレース情報を伝播させるための インターフェース HTTPリクエスト/レスポンスヘッダーや メッセージキューのメタデータ などの テキスト形式で情報( = carrier) をやりとりする場面で利用 Inject 関数 現在の context(もしくは指定されたもの) からコンテキスト情報を取得して 指定の setter 関数を使って carrier に コンテキスト情報を書き込む どんな情報を書き込んでいるか? 引用:https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-api/src/opentelemetry/trace/propagation/tracecontext.py

Slide 19

Slide 19 text

せっかくなのでコードを見てみる Pub/Sub Client のコード start_create_spant 関数 Tracer を取得してスパンを生成 ・ユーザーがパブリッシュした _message.data ・ attributes には色々含まれている Event のスパンへの紐付け TraceContextTextMapPropagator で伝播 ・Pub/Sub に送られるメッセージの attributes key の googleclient_traceparent を つっこんでいる → よくあるスパン生成とメッセージへの コンテキスト伝播が実直に行われていた 引用:https://github.com/googleapis/python-pubsub/blob/main/google/cloud/pubsub_v1/open_telemetry/publish_message_wrapper.py

Slide 20

Slide 20 text

Pub/Sub をメッセージキューとして採用した非同期処理を構築 ● 非同期処理では処理が分断されることでトラシューが面倒に ● 分散トレーシングもコンテキストが損失されることで一連にならない Pub/Sub Client の Otel オプションの有効化で非同期処理でも分散トレーシング ● オプションの有効化によってコンテキストがメッセージに含められる ● 内部では TextMapPropagator が carrier へのコンテキスト書き込みをやってくれている → 非同期処理でも楽しいトラブルシューティングライフが送りましょう! まとめと学び

Slide 21

Slide 21 text

CREDITS: This presentation template was created by Slidesgo, and includes icons by Flaticon, and infographics & images by Freepik Thanks! 21 @pHaya72 @t_hayashi