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
マイクロサービスの効率的な監視〜不安定な依存先との闘い〜
Search
Tao Watanabe
September 20, 2023
Programming
2.9k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
マイクロサービスの効率的な監視〜不安定な依存先との闘い〜
DMM.go #6 の登壇資料です。
https://dmm.connpass.com/event/295065/
Tao Watanabe
September 20, 2023
More Decks by Tao Watanabe
See All by Tao Watanabe
オンプレMySQLをTiDB Cloudへ移行した手順紹介 @TiUG #0
taowata
0
500
Other Decks in Programming
See All in Programming
生成AI導入の「期待外れ」を乗り越える ー 開発フロー改革が目指す、真の組織変革
starfish719
0
1.6k
Terraform標準の組織で AWS CDKをどう使うか
mu7889yoon
1
330
5分で問診!Composer セキュリティ健康診断
codmoninc
0
500
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
5.1k
共通化で考えるべきは、実装より公開する型だった
codeegg
0
270
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.9k
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.7k
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
140
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
180
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
150
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
170
フィードバックで育てるAI開発
kotaminato
1
120
Featured
See All Featured
GraphQLとの向き合い方2022年版
quramy
50
15k
New Earth Scene 8
popppiees
3
2.4k
Rails Girls Zürich Keynote
gr2m
96
14k
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
340
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
Utilizing Notion as your number one productivity tool
mfonobong
4
440
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.2k
Between Models and Reality
mayunak
4
380
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
610
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
440
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Transcript
© DMM マイクロサービスの効率的な監視 〜不安定な依存先との闘い〜 DMM.go #6 プラットフォーム事業本部 Tao Watanabe 1
© DMM 自己紹介 入社:2022年 新卒入社 所属:プラットフォーム事業本部 マイクロサービスアーキテクトグループ 認証チーム 最近はオンプレMySQL→TiDB Cloud
への 移行プロジェクトに注力しています 2 Tao Watanabe X: @tao_wata
© DMM • DMM プラットフォーム (PF)と マイクロサービスアーキテクトグループの紹介 • 認証認可基盤の紹介 •
認証認可基盤の運用・監視における辛み • それを解消した方法 • 結果と課題・まとめ Agenda 3
© DMM プラットフォーム(PF)事業本部とは DMMの各サービスが利用する共通機能を開発する組織 4 会員登録 ログイン 不正対策 ポイント 購入
決済 継続課金 など カスタマー サポート 120人規模のエンジニア組織
© DMM PF事業本部が長年抱えていた課題 5 組織規模が大きいため、マイクロサービスアーキテクチャを 以前から採用 → 各サービスの開発チームのテクノロジースタックがサイロ化 → 開発効率を上げられない、共通の技術課題を解決できない
これを解決するためマイクロサービスアーキテクトグループが発足
© DMM マイクロサービスアーキテクトグループ 6 DMMプラットフォームにおける開発組織戦略を策定・実行し、 開発効率・セキュリティレベル向上を実現する 以下のエコシステムを提供 • マイクロサービスプラットフォーム (Kubernetesクラスタ)
• 負荷試験基盤 • 監視機能(Datadog) • 認証認可機能 • SLO/SLIの導入 • レビューシステム など
© DMM PFのマイクロサービスアーキテクチャの概要 7 API Gateway 認可サービス 認証サービス 決済サービス 会員サービス
認証認可基盤 …
© DMM 認証認可基盤 8 DMM会員をはじめ、従業員や各アプリケーションが持つリソースに対する認証と認可を 一元管理する基盤。 オンプレのレガシーシステムをプロキシしている 使用技術 言語: Go
インフラ: Kubernetes(GKE) CI: GitHub Actions CD: ArgoCD 監視: Datadog GKE オンプレ API Gateway 認証認可基盤 認証サービス 認可サービス DMMの成長を 支えてきた レガシーシステム
© DMM 認証認可基盤が果たす役目 9 • 段階的なリプレイス先 • 新機能の追加先
© DMM 段階的なリプレイス先 10 レガシーシステムの段階的なリプレイスを容易にする GKE オンプレ API Gateway 認証認可基盤
認証サービス 認可サービス エンドポイントごとの リプレイスが容易
© DMM 新機能の追加先 11 認証認可機能の追加を開発効率よく実現する GKE オンプレ API Gateway 認証認可基盤
認証サービス 認可サービス 新しい 認証・認可機能ニー ズ エコシステムを利 用し 生産性高く開発で きる 古いシステムで 改修が難しい
© DMM 認証認可基盤が果たす役目 12 認証認可機能の負債脱却のための中心的な役割 一方で、リプレイスが進むまでは単なるProxy → 認証認可機能のオーナーシップはProxy先のシステムを管轄するチーム にあるという状況
© DMM 認証認可基盤の運用で どんな困難があったか
© DMM 当初はAPI Gatewayのエンドポイントを監視 14 API Gateway 認証認可基盤 (自サービス) レガシー
システム リバース プロキシ Redis Redis API Gatewayのエンドポイントを起点とし レイテンシを監視 合計 100ms 10ms 5ms 35ms オンプレ 50ms
© DMM 監視・運用における辛さ・難しさ • 依存先レガシーシステム起因のアラートで夜中に起こされる • 依存元API Gatewayの不調にも影響される • 自サービス自体の品質が分からない
15
© DMM 辛い例①
© DMM レガシーシステムのレイテンシが悪化 17 API Gateway 認証認可基盤 (自サービス) レガシー システム
リバース プロキシ Redis Redis レイテンシ悪化でアラート発火 10ms 5ms 35ms レイテンシ悪 化 オンプレ
© DMM an incident occurs …
© DMM 他チーム管轄のプロダクトが原因 19 API Gateway 認証認可基盤 (自サービス) レガシー システム
リバース プロキシ Redis Redis 10ms 5ms 35ms レイテンシ悪 化 自チームの管轄 他チームの管轄
© DMM やれることがない...
© DMM 辛い例②
© DMM 依存元のAPI Gatewayの不調 22 API Gateway 認証認可基盤 (自サービス) レガシー
システム リバース プロキシ Redis Redis 5ms 35ms オンプレ 50ms レイテンシ悪 化 レイテンシ悪化でアラート発火
© DMM an incident occurs …
© DMM API Gatewayも他チーム管轄 24 API Gateway 認証認可基盤 (自サービス) レガシー
システム リバース プロキシ Redis Redis 5ms 35ms 50ms レイテンシ悪 化 自チームの管轄 他チームの管轄
© DMM やれることがない...
© DMM 辛い例③
© DMM オンプレのリバースプロキシの不調 27 API Gateway 認証認可基盤 (自サービス) レガシー システム
リバース プロキシ Redis Redis 5ms 10ms オンプレ 50ms レイテンシ悪 化 レイテンシ悪化でアラート発火
© DMM an incident occurs …
© DMM やれることはない...
© DMM 作業効率・モチベーションの低下 他チーム管轄サービス起因でアラートが発火 →結果、不必要な対応を迫られることもある 30
© DMM これを解決するために 割り切った戦略を採用
© DMM 割り切った戦略を採用 自サービスのレイテンシしか見ない 32
© DMM API Gatewayと依存先システムのレイテンシは含めず監視 33 API Gateway 認証認可基盤 (自サービス) レガシー
システム リバース プロキシ Redis Redis 10ms 5ms 35ms オンプレ 50ms
© DMM Goでどのように実装をしたか 注意: Goのプラクティスに反する方法を利用しています
© DMM Goのプラクティスに反した方法 Contextにtime.Durationへの参照を付加し、 http.Clientの中で外部APIへのリクエスト待ち時間を都度Contextの参照先 へ加算する 基本的にcontext.WithValue()では、一連のリクエストにおいて不変の値を 伝搬するべきです!!! 外部APIへ依存する箇所にすでにctxを引き回していたので 実装が楽だった...
35
© DMM リクエストシーケンス 36 自サービス
© DMM 自サービスのレイテンシを算出 37 自サービスのレイテンシを 全体処理時間 - 依存先システムのレスポンスを待つ時間の総計(外部処理 時間) として算出
© DMM 38 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 Contextの参照先の値を取得 内部処理時間計算 外部処理時間
計測開始 外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェアとHTTPクライアントで処理時間を計測 ctx ctx
© DMM 39 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 Contextの参照先の値を取得 内部処理時間計算 外部処理時間
計測開始 外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェアで全体処理時間の計測を開始 ctx ctx
© DMM type Store struct { UserID string TraceID string
TotalExternalDuration time.Duration } type storeKeyType struct{} var storeKey = storeKeyType{} 40 func MiddlewareDuration(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { start := time.Now() store := &Store{} ctx := context.WithValue(ctx, storeKey, store) next.ServeHTTP(rw, r.WithContext(ctx)) wholeDuration := time.Now().Sub(start) internalDuration := wholeDuration - store.TotalExternalDuration if span, ok := tracer.SpanFromContext(r.Context()); ok { span.SetTag("internal.duration", internalDuration.Microseconds()) } }) } ミドルウェアで全体処理時間の計測を開始 ①Contextに格納して伝搬する値 をまとめた構造体と そのKeyを定義する ⚠可変の値として外部処理時間の総 計が含まれる ②全体処理時間の計測開始 ④ContextにValue(*Store)を セット ③Storeのポインタを生成
© DMM RoundTripperで外部処理時間の計測 41 全体処理時間 計測開始 Contextに*Storeをセット 全体処理時間計測終了 内部処理時間計算 外部処理時間
計測開始 外部処理時間 計測終了 *Storeを更新
© DMM RoundTripperで外部処理時間の計測 42 type durationRoundTripper struct { base http.RoundTripper
} func (rt *durationRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { start := time.Now() res, err := rt.base.RoundTrip(req) duration := time.Since(start) store := GetStoreFromContext(req.Context()) store.TotalExternalDuration += duration return res, err } func WrapClientWithDurationRoundTripper(c *http.Client) *http.Client { if c.Transport == nil { c.Transport = http.DefaultTransport } c.Transport = &durationRoundTripper{base: c.Transport} return c } ①外部処理時間を計測する ②ContextからStoreの参照を取り出す ③外部処理時間の総計に算出した外部処理時間を加算する ④ 以上の処理を追加したRoundTripperでCllientを ラップする
© DMM 43 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 内部処理時間計算 外部処理時間 計測開始
外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェア(帰り)で内部処理時間を算出 ctx ctx
© DMM type Store struct { UserID string TraceID string
TotalExternalDuration time.Duration } type storeKeyType struct{} var storeKey = storeKeyType{} 44 func MiddlewareDuration(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { start := time.Now() store := &Store{} ctx := context.WithValue(ctx, storeKey, store) next.ServeHTTP(rw, r.WithContext(ctx)) wholeDuration := time.Now().Sub(start) internalDuration := wholeDuration - store.TotalExternalDuration if span, ok := tracer.SpanFromContext(r.Context()); ok { span.SetTag("internal.duration", internalDuration.Microseconds()) } }) } ミドルウェア(帰り)で内部処理時間を算出 ①全体処理時間の算出 ②(全体処理時間 - 外部処理時間の総計) を計算し、 内部処理時間を算出 ③トレーシングライブラリのSpanに 時間を付与する
© DMM 自サービスの内部処理時間のみを監視 45 API Gateway 認証認可基盤 (自サービス) レガシー システム
リバース プロキシ Redis Redis 10ms 5ms 35ms オンプレ 50ms
© DMM 静かな夜を手に入れた 自分達では対処できない不具合によるアラート対応が減った 思い切った監視に切り替えた結果... 46
© DMM spanに内部処理時間を付与したことで、シークバーで絞り込めるようになった → 自チーム管轄のRedisの遅延などによる内部処理の遅れ, 不具合を 検知できるようになった 思い切った監視に切り替えた結果... 47
© DMM 課題 GoのContextの使い方 ✖ Contextに可変な値(TotalExternalDuration)を付加する方法で解決したこ と middlewareとhttp.ClientがContextの値を介して結合度が高くなってしまっ たのも気になる → 今後負債化するかも
基本的にcontext.WithValue()では、一連のリクエストにおいて不変の値を 伝搬するべきです!!! 48
© DMM 課題 マイクロサービスのオーナーシップ 今回自サービスの責任範囲のみに監視対象を絞る戦略を採用したが... 依存先も含めたサービスの品質に誰かは責任を持たなければならない ユーザーに提供する機能のオーナーシップを持つ人は誰? 負債脱却中はこの辺りの責任範囲が難しい 49
© DMM まとめ 何らかのProxyや共通基盤の場合、依存先システムの監視を切り捨て、 自サービス自体の可用性を監視すれば必要十分なこともある Contextの誤用・濫用はやめよう Contextの使い方はよく議論されている (トレードオフな部分もあるのでは) 50
© DMM ご静聴ありがとうございました