Upgrade to Pro — share decks privately, control downloads, hide ads and more …

20260705_ADOTでLambdaを観測してみた.pdf

Avatar for Hiroshi Kato Hiroshi Kato
July 02, 2026
51

 20260705_ADOTでLambdaを観測してみた.pdf

Avatar for Hiroshi Kato

Hiroshi Kato

July 02, 2026

More Decks by Hiroshi Kato

Transcript

  1. OTel(OpenTelemetry)を初めて知る 「システムの内部を標準化された形式で観測できる」 OpenTelemetry = オブザーバビリティの標準規格 Traces リクエストの全体の流れ 処理ごとの所要時間 Metrics 数値データ

    CPU・レイテンシー・エラー率 Logs テキストログ アプリケーション出力 ポイント • ベンダー依存しない → Datadog / New Relic / Grafana 等、どこにでも送れる • Traces / Metrics / Logs を同じ形式で収集できる → 計測の仕方を標準化する規格、バックエンドは自由に選べる
  2. 振り返り 前回やったこと • TelemetryAPI を購読する自作 Extension を実装 • Lambda の

    INIT フェーズの内訳が見えた - Extension Init - Runtime Init - Module Import • 各処理を個別に計測できることを確認 前回の結論 • 自作で仕組みは理解できた • ADOTを使えばいい! (AWSが公式に配布するOTel Collector) → 今回は「ADOT(AWS Distro for OpenTelemetry)」を実際に試してみた
  3. X-Ray SDK が終わる 2026年2月25日、メンテナンスモード入り X-Ray SDK / Daemon の一般提供が終了 X-Rayサービスがなくなるわけではない

    SDK(送信手段)が終わる → 送り方が変わる 新しい送り方 = OpenTelemetry(ADOT経由でX-Rayに送る) Lambda + X-Ray SDK → X-Ray 旧(廃止予定) Lambda + ADOT → X-Ray / Datadog / Grafana 新(OTel標準)
  4. 検証ロードマップ ゼロから段階的に Lambda の可視性を上げていく 0 素のLambda 合計値のみ 1 X-Rayトレース 箱が見える

    2 ADOT + カスタムspan 内部が全部見える 3 Application Signals 依存関係マップ 観測なし ───────────────────────────────────→ フル観測
  5. 0 素のLambda(観測なし) S3 + DynamoDB を呼ぶシンプルな関数 # INIT フェーズ s3_client

    = boto3.client('s3') table = dynamodb.Table('otel-lambda-demo') time.sleep(0.3) # 擬似的に重い初期化 # INVOKE フェーズ def lambda_handler(event, context): time.sleep(0.05) # バリデーション s3_client.list_buckets() table.put_item(...) table.get_item(...) 見えるもの ✓ Init Duration(合計値) ✓ Duration(合計値) ✓ 手動printログ 見えないもの ✗ S3 に何ms かかった? ✗ DynamoDB に何ms? ✗ なぜ遅い回がある? ✗ ボトルネックの特定 → 「何が遅いか」は合計値からは分からない
  6. 0 コールドスタート3回の結果 1回目 2回目 3回目 Init Duration 714 ms 838

    ms 730 ms Duration 569 ms 652 ms 591 ms → 120msのばらつき。でも「なぜ」は分からない
  7. 1 X-Rayトレースを有効化 見えるようになったこと ✓ Init / Function / Overhead の区分

    ✓ 全体の所要時間(1.58秒) まだ見えないこと ✗ Init の内訳 ✗ S3 / DynamoDB の個別呼び出し ✗ ボトルネックの特定 なぜ見えないのか X-Ray SDK を入れていないため、boto3呼び出しは サブセグメントとして記録されない トレースはLambdaサービス側の計測のみ
  8. 2 ADOT レイヤーを導入する ❶ レイヤー追加 aws-otel-python-arm64-ver-1-32-0:2 ❷ 環境変数 AWS_LAMBDA_EXEC_WRAPPER =

    /opt/otel-instrument ❸ コードにspan追加 with tracer.start_as_current_span('操作名'): ADOT の仕組み Lambda 関数コード → OTel SDK (自動計装) → ADOT Collector (Extension) → X-Ray / CloudWatch レイヤー内に SDK + Collector が同梱、/opt/otel-instrument がエントリポイントをラップ
  9. 2 カスタムspan — with文で囲むだけ Before # S3操作 response = s3_client.list_buckets()

    bucket_count = len(response['Buckets']) # DynamoDB書き込み table.put_item(Item={...}) After(ADOT) # S3操作 — spanで囲むだけ with tracer.start_as_current_span('list_s3_buckets') as span: response = s3_client.list_buckets() span.set_attribute('bucket.count', bucket_count) # DynamoDB — 同様に囲む with tracer.start_as_current_span('write_dynamodb') as span: table.put_item(Item={...}) span.set_attribute('item.id', item_id) 得られる可視性 ✓ 各操作がX-Rayタイムラインに表示 ✓ 処理時間が自動計測 ✓ boto3呼び出しも自動で子span化 with ... as span: 処理時間を自動計測(開始〜終了) span.set_attribute() 補足情報をタグ付け(任意)
  10. 2 気になるオーバーヘッド 128MB / arm64 での計測 素のLambda ADOT (Cold) ADOT

    (Warm) Init Duration ~760 ms 1,488 ms — Invoke Duration ~600 ms 4,418 ms 903 ms メモリ使用 98 MB 124 MB 124 MB なぜ初回が重いのか • /opt/otel-instrument が Python の起動をフック → OTel SDK を inject • 全自動計装ライブラリ (botocore, urllib3, sqlalchemy...) が import される • 不要な計装(sqlalchemy等)もimportされる → 初期化コストの一因 • Warm start ではこれらが全てキャッシュ済み → オーバーヘッド最小化 結論: ウォームスタートなら +300ms 程度、可視性を得るコストとして十分許容範囲
  11. 3 Application Signals を有効化 (1)レイヤー変更 検証2: aws-otel-python-arm64-ver-1-32-0:2 検証3: AWSOpenTelemetryDistroPython:28 ←

    Application Signals対応版 (2)追加設定: Lambda設定 → アプリケーションシグナル = 有効(コード変更なし) パフォーマンス Cold: Init 1,241ms / Duration 725ms Warm: Duration 589ms ≈ 素のLambdaと同等! → App Signals版の方がADOT単体より軽い 追加で得られるもの ✓ 依存関係マップ(自動生成) 構成の変化 検証2: Lambda → OTel SDK → ADOT Collector → X-Ray 検証3: Lambda → OTel SDK → X-Ray ↑ Collector (Extension) Collector不要(直接送信)
  12. まとめ 可視化のトレードオフ 可視性 Cold Start Warm メモリ 0 素のLambda なし

    ベースライン ベースライン 98 MB 1 サービストレース 低 変わらず 変わらず 変わらず 2 ADOT + span 高 +730 ms +300 ms 124 MB 3 App Signals 最高 +480 ms ほぼゼロ 108 MB → App Signals が最もバランスが良い(可視性最高 × ウォーム時コストほぼゼロ) • ADOTの導入は「レイヤー + 環境変数 + with文」だけ • ウォームスタートならオーバーヘッドは無視できるレベル • App Signals版はCollector不要で軽量(検証2より改善) • X-Ray SDK が終わる今が移行のベストタイミング • OTel標準に乗れば将来バックエンドを自由に選べる