Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
マイクロサービスの効率的な監視〜不安定な依存先との闘い〜
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
520
Other Decks in Programming
See All in Programming
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
170
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
290
kubernetes コンポーネント開発入門 / 新卒N年目の勉強会&交流会!〜〇〇への誘い〜 #n_study
mazrean
0
220
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
150
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
150
Jetpack Compose メカニズム
skydoves
0
250
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
700
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
110
XHTMLが残したもの
yosuke_furukawa
PRO
2
740
AI に Inclusive UI を書かせよう — Design Rules Skill で Compose UI を作り直す
theoriatec2024
1
480
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
140
App Intentsのビルドプロセスを支える技術
kntkymt
0
330
Featured
See All Featured
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
230
Git: the NoSQL Database
bkeepers
PRO
432
67k
Exploring anti-patterns in Rails
aemeredith
3
500
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
The Invisible Side of Design
smashingmag
301
52k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
The World Runs on Bad Software
bkeepers
PRO
72
12k
We Have a Design System, Now What?
morganepeng
55
8.3k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
410
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
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 ご静聴ありがとうございました