Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ABEMAの安定稼働を支えたOpenTelemetryの導入事例
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Miyazaki Taiga
March 10, 2023
9
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
ABEMAの安定稼働を支えたOpenTelemetryの導入事例
Miyazaki Taiga
March 10, 2023
More Decks by Miyazaki Taiga
See All by Miyazaki Taiga
SRE チームの再出発 / ゆるSRE #16
mk2taiga
2
640
30時間限界突破フェスに向 けた SRE の取り組み
mk2taiga
0
45
ABEMAの本番環境負荷試験への挑戦
mk2taiga
6
3.1k
Featured
See All Featured
Exploring anti-patterns in Rails
aemeredith
3
400
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
720
Balancing Empowerment & Direction
lara
6
1.1k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
430
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
Build your cross-platform service in a week with App Engine
jlugia
234
18k
Abbi's Birthday
coloredviolet
2
8k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
380
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
210
Transcript
AbemaTV, Inc. All Rights Reserved AbemaTV, Inc. All Rights Reserved
1 ABEMAの安定稼働を支えた OpenTelemetryの導入事例 2023 March 10th Taiga Miyazaki
AbemaTV, Inc. All Rights Reserved 宮﨑 大芽 2022 年 中
途 入 社 。 ABEMAのバックエンドエンジニアとしてサービス開発に従事。 FIFA ワールドカップ カタール 2022 に向けた開発期間中では、サービスの負荷対策や 障害対策に携わり、現在はプロダクト基盤チームで決済システムの開発に携わる。 趣味は、漫画やアニメ。映画ブルージャイアントがおすすめ。 2 Profile
AbemaTV, Inc. All Rights Reserved 3 1. 背景 2. OpenTelemetry
概要 3. 導入方法 4. 既存システムに導入する上で苦労した点 5. 活用事例 6. 今後の展望 INDEX
AbemaTV, Inc. All Rights Reserved 背景 4
AbemaTV, Inc. All Rights Reserved ポイント 背景 5 • ABEMA
はマイクロサービスアーキテクチャを適用している • W杯に向けた負荷試験では、サービス全体に対する複合的な負荷試験を行った • 負荷試験を開始した当初は、サービス全体に対して分散トレーシングが導入され ていなかった ◦ 複雑なマイクロサービスの分析が難しい
AbemaTV, Inc. All Rights Reserved OpenTelemetry 概要 6
AbemaTV, Inc. All Rights Reserved 特徴 OpenTelemetry 概要 7 •
ベンダーに依存しない • OpenTracing, OpenCensus の後継 • テレメトリデータを計測・生成・収集・エクスポートに利用
AbemaTV, Inc. All Rights Reserved 8 Cloud Trace の画面 OpenTelemetry
概要
AbemaTV, Inc. All Rights Reserved 導入方法 9
AbemaTV, Inc. All Rights Reserved 導入方法 10 • Application は
Kubernetes (GKE) で稼働 • Anthos Service Mesh (ASM) 導入済み ◦ Istio ベースの Service Mesh ◦ 基本的に Application の通信は Sidecar として挿入されている istio-proxy (envoy) 経由で送受信される 前提
AbemaTV, Inc. All Rights Reserved 11 概念図 導入方法 LB istio-proxy
container application container Cloud Trace istio-proxy container application container … Spans gRPC request HTTP microservice A microservice B Instrumentation (OpenTelemetry)
AbemaTV, Inc. All Rights Reserved 導入方法 12 • istio-proxy が
Sidecar として起動している Pod で tracing が可能 • ASM が対応している Trace Context のフォーマット ◦ W3C TraceContext ◦ Zipkin B3 ◦ Google Cloud Trace ◦ gRPC TraceBin Anthos Service Mesh (ASM) との連携
AbemaTV, Inc. All Rights Reserved 導入方法 13 • context が正しく伝播されていないレガシーコードの修正
• レガシーコードが古い google.golang.org/grpc に依存している問題の解消 • 初期スコープでは Trace Context の伝播と ASM の連携を目標とした • 最終的に各ミドルウェアのクライアント用の instrumentation library の導入、span exporter の設定を行う方針 既に稼働しているサービスへの段階的導入
AbemaTV, Inc. All Rights Reserved 導入方法 14 • otelhttp •
otelgrpc • redisotel • otelmongo ABEMA で利用した instrumentation library (一部)
AbemaTV, Inc. All Rights Reserved 導入方法 15 • otelhttp •
otelgrpc • redisotel • otelmongo ABEMA で利用した instrumentation library (一部)
AbemaTV, Inc. All Rights Reserved 導入方法 16 • otelhttp •
otelgrpc • redisotel • otelmongo ABEMA で利用した instrumentation library (一部)
AbemaTV, Inc. All Rights Reserved 導入方法 17 otelhttp (server) func
newHandler(api *ResourceAPI) http.Handler { mux := http.NewServeMux() mux.HandleFunc("/", api.healthCheck) mux.HandleFunc("/readiness", api.readinessHandler) mux.HandleFunc("/path/to/resource", api.saveResource) var h http.Handler = mux h = otelMiddleware(h) return h } func otelMiddleware(next http.Handler) http.Handler { return otelhttp.NewHandler(next, "server", otelhttp.WithMessageEvents(otelhttp.ReadEvents, otelhttp.WriteEvents), otelhttp.WithFilter( filters.All( // ignore health check endpoints filters.Not(filters.Path("/")), filters.Not(filters.Path("/readiness")), ), ), ) } ヘルスチェックのリクエストは無視 する
AbemaTV, Inc. All Rights Reserved 導入方法 18 otelhttp (client) func
request(ctx context.Context) error { req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com", http.NoBody) if err != nil { return err } cli := &http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport), Timeout: 5 * time.Second, } resp, err := cli.Do(req) if err != nil { return err } defer resp.Body.Close() return nil } transport を wrap する
AbemaTV, Inc. All Rights Reserved 導入方法 19 • otelhttp •
otelgrpc • redisotel • otelmongo ABEMA で利用した instrumentation library (一部)
AbemaTV, Inc. All Rights Reserved 導入方法 20 otelgrpc (server) func
newServer(hs health.HealthServer, service v1.AppServiceServer) *grpc.Server { s := grpc.NewServer( grpc_middleware.WithUnaryServerChain( otelgrpc.UnaryServerInterceptor( otelgrpc.WithInterceptorFilter( // ignore health check request filters.Not(filters.HealthCheck()), ), ), ), grpc_middleware.WithStreamServerChain( otelgrpc.StreamServerInterceptor( // ignore health check request filters.Not(filters.HealthCheck()), ), ), ) health.RegisterHealthServer(s, hs) v1.RegisterAppServiceServer(s, service) reflection.Register(s) return s } interceptor を追加 stream も同様 ヘルスチェックの リクエストは無視する
AbemaTV, Inc. All Rights Reserved 導入方法 21 otelgrpc (client) func
newClient(ctx context.Context, addr string) (*grpc.ClientConn, error) { otelgrpc.UnaryClientInterceptor() dialOpts := []grpc.DialOption{ grpc.WithUserAgent("service/1.0.0"), grpc_middleware.ChainUnaryClient(otelgrpc.UnaryClientInterceptor()), grpc_middleware.ChainStreamClient(otelgrpc.StreamClientInterceptor()), } return grpc.DialContext(ctx, addr, dialOpts...) } interceptor を追加
AbemaTV, Inc. All Rights Reserved 導入方法 22 • OpenCensus Bridge
を導入 • Google Cloud のサービス (Pub/Sub、Spanner、Bigtable、Firestore…) へのリクエストを可視化 Google Cloud Client Libraries との連携
AbemaTV, Inc. All Rights Reserved 導入方法 23 initialize tracer provider
① func init() { otel.SetTextMapPropagator( b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader))) // OpenCensus Bridge tracer := otel.Tracer("go.opentelemetry.io/otel/bridge/opencensus") octrace.DefaultTracer = opencensus.NewTracer(tracer) } func NewTracerProvider() (trace.TracerProvider, func()) { opts := []sdktrace.TracerProviderOption{ sdktrace.WithBatcher(newCloudTraceExporter()), sdktrace.WithSampler(sdktrace.TraceIDRatioBased(fraction)), } tp := sdktrace.NewTracerProvider(opts...) otel.SetTracerProvider(tp) cleanup := func() { ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() if err := tp.Shutdown(ctx); err != nil { log.Printf("[ERROR]: %v", err) } } return tp, cleanup } Trace Context の伝播 Google Cloud Client Library 対応 Tracer Provider 初期化
AbemaTV, Inc. All Rights Reserved 導入方法 24 initialize tracer provider
② func newCloudTraceExporter() sdktrace.SpanExporter { exporter, err := texporter.New() if err != nil { log.Printf("[ERROR]: fallback to noop exporter: %v", err) return newNoopExporter() } return exporter } func newNoopExporter() sdktrace.SpanExporter { return &noopExporter{} } type noopExporter struct{} func (*noopExporter) ExportSpans(context.Context, []sdktrace.ReadOnlySpan) error { return nil } func (*noopExporter) Shutdown(context.Context) error { return nil } 失敗時に Application が起動しないと困るので 何 もしない exporter に fallback Cloud Trace Exporter の初期化
AbemaTV, Inc. All Rights Reserved 導入方法 25 • custom sampler
を実装して、ノイズになる一部の span を無視する • 既に導入されている logging library を go.opentelemetry.io/otel でも利用するために github.com/go-logr/logr との bridge を実装 細かい対応
AbemaTV, Inc. All Rights Reserved 既存システムに導入する上で苦労した点 26
AbemaTV, Inc. All Rights Reserved 既存システムに導入する上で苦労した点 27 • Trace Context
が伝播することの検証 ◦ Zipkin B3 Single Header には対応してないことが判明 ◦ 既存の Application で context が伝播されていない箇所が判明 (後述) • ASM 側で有効にするだけでは Tracing は利用できない ◦ Application 側の対応も必要 Anthos Service Mesh (ASM) との連携
AbemaTV, Inc. All Rights Reserved 28 Anthos Service Mesh (ASM)
との連携 既存システムに導入する上で苦労した点 istio-proxy container application container Microservic B Middleware … Trace Context Microservice A LB
AbemaTV, Inc. All Rights Reserved 29 Anthos Service Mesh (ASM)
との連携 既存システムに導入する上で苦労した点 istio-proxy container application container Middleware … Trace Context Microservice A Microservic B LB
AbemaTV, Inc. All Rights Reserved 既存システムに導入する上で苦労した点 30 • そもそも context
が渡されていない関数呼び出しがあった • context.Background() や context.TODO() で渡されている箇所 context が正しく伝播されていないレガシーコードの修正
AbemaTV, Inc. All Rights Reserved 31 context の伝播 - Before
既存システムに導入する上で苦労した点 func (a *ResourceAPI) saveResource(w http.ResponseWriter, r *http.Request) { dec := json.NewDecoder(r.Body) defer r.Body.Close() p := new(SaveParam) if err := dec.Decode(p); err != nil { w.WriteHeader(http.StatusBadRequest) return } // 同期処理 if err := a.svc.Save(p); err != nil { w.WriteHeader(http.StatusInternalServerError) return } // 非同期処理 go func() { if err := a.svc.Update(context.Background(), &UpdateParam{}); err != nil { log.Printf("[ERROR]: %v", err) } }() } context が渡されていない 上流の context が 渡されていない
AbemaTV, Inc. All Rights Reserved 32 context の伝播 - After
既存システムに導入する上で苦労した点 func (a *ResourceAPI) saveResource(w http.ResponseWriter, r *http.Request) { dec := json.NewDecoder(r.Body) defer r.Body.Close() p := new(SaveParam) if err := dec.Decode(p); err != nil { w.WriteHeader(http.StatusBadRequest) return } // 同期処理 ctx := r.Context() if err := a.svc.Save(ctx, p); err != nil { w.WriteHeader(http.StatusInternalServerError) return } // 非同期処理 go func() { bg := trace.ContextWithSpan(context.Background(), trace.SpanFromContext(ctx)) if err := a.svc.Update(bg, &UpdateParam{}); err != nil { log.Printf("[ERROR]: %v", err) } }() } context を渡す context に Span をコピー
AbemaTV, Inc. All Rights Reserved 既存システムに導入する上で苦労した点 33 • レガシーコードが google.golang.org/grpc
v1.29.1 に依存 ◦ google.golang.org/grpc/naming に依存しているため ▪ ASM 導入により k8s Watch API を使用しなくなり不要に • otelgrpc は google.golang.org/grpc/credentials/insecure に依存 ◦ google.golang.org/grpc v1.34.0 で追加された 古い google.golang.org/grpc への依存
AbemaTV, Inc. All Rights Reserved 活用事例 34
AbemaTV, Inc. All Rights Reserved 活用事例 35 • DB が遅くないのに
API の duration が遅い • istio-proxy container がボ トルネックとなっていた 負荷試験
AbemaTV, Inc. All Rights Reserved 活用事例 36 試合中の監視
AbemaTV, Inc. All Rights Reserved 今後の展望 37
AbemaTV, Inc. All Rights Reserved 今後の展望 38 • Application が特定のソリューションに依存することを防ぐ
◦ 特定のソリューション: Cloud Trace, AWS X-Ray 等 • Infrastructure で共通のメタデータの付与 • パフォーマンスの最適化 OpenTelemetry Collector 導入
AbemaTV, Inc. All Rights Reserved 今後の展望 39 • マルチクラウド (Google
Cloud, AWS) を想定した構成 ◦ クラウド横断でのトレーシング • コストコントロール ◦ 柔軟な保存期間 Grafana Tempo 導入
AbemaTV, Inc. All Rights Reserved まとめ 40
AbemaTV, Inc. All Rights Reserved まとめ 41 • マイクロサービスのボトルネックの把握のために、 OpenTelemetry
を用いた 分散トレーシングを実現 • ASM, OpenCensus Bridge, 各種 library を用いて導入を行った • 負荷試験や監視時に活用し、FIFA ワールドカップ カタール 2022 を乗り切る ことができた
AbemaTV, Inc. All Rights Reserved ご清聴ありがとうございました 42