Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

マイクロサービスの効率的な監視〜不安定な依存先との闘い〜

Tao Watanabe
September 20, 2023

 マイクロサービスの効率的な監視〜不安定な依存先との闘い〜

DMM.go #6 の登壇資料です。
https://dmm.connpass.com/event/295065/

Tao Watanabe

September 20, 2023
Tweet

More Decks by Tao Watanabe

Other Decks in Programming

Transcript

  1. © DMM • DMM プラットフォーム (PF)と マイクロサービスアーキテクトグループの紹介 • 認証認可基盤の紹介 •

    認証認可基盤の運用・監視における辛み • それを解消した方法 • 結果と課題・まとめ Agenda 3
  2. © DMM 認証認可基盤 8 DMM会員をはじめ、従業員や各アプリケーションが持つリソースに対する認証と認可を 一元管理する基盤。 オンプレのレガシーシステムをプロキシしている 使用技術 言語: Go

    インフラ: Kubernetes(GKE) CI: GitHub Actions CD: ArgoCD 監視: Datadog GKE オンプレ API Gateway 認証認可基盤 認証サービス 認可サービス DMMの成長を 支えてきた レガシーシステム
  3. © DMM 新機能の追加先 11 認証認可機能の追加を開発効率よく実現する GKE オンプレ API Gateway 認証認可基盤

    認証サービス 認可サービス 新しい 認証・認可機能ニー ズ エコシステムを利 用し 生産性高く開発で きる 古いシステムで 改修が難しい
  4. © DMM 当初はAPI Gatewayのエンドポイントを監視 14 API Gateway 認証認可基盤 (自サービス) レガシー

    システム リバース プロキシ   Redis   Redis API Gatewayのエンドポイントを起点とし レイテンシを監視 合計 100ms 10ms 5ms 35ms オンプレ 50ms
  5. © DMM レガシーシステムのレイテンシが悪化 17 API Gateway 認証認可基盤 (自サービス) レガシー システム

    リバース プロキシ   Redis   Redis レイテンシ悪化でアラート発火 10ms 5ms 35ms レイテンシ悪 化 オンプレ
  6. © DMM 他チーム管轄のプロダクトが原因 19 API Gateway 認証認可基盤 (自サービス) レガシー システム

    リバース プロキシ   Redis   Redis 10ms 5ms 35ms レイテンシ悪 化 自チームの管轄 他チームの管轄
  7. © DMM 依存元のAPI Gatewayの不調 22 API Gateway 認証認可基盤 (自サービス) レガシー

    システム リバース プロキシ   Redis   Redis 5ms 35ms オンプレ 50ms レイテンシ悪 化 レイテンシ悪化でアラート発火
  8. © DMM API Gatewayも他チーム管轄 24 API Gateway 認証認可基盤 (自サービス) レガシー

    システム リバース プロキシ   Redis   Redis 5ms 35ms 50ms レイテンシ悪 化 自チームの管轄 他チームの管轄
  9. © DMM オンプレのリバースプロキシの不調 27 API Gateway 認証認可基盤 (自サービス) レガシー システム

    リバース プロキシ   Redis   Redis 5ms 10ms オンプレ 50ms レイテンシ悪 化 レイテンシ悪化でアラート発火
  10. © DMM 38 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 Contextの参照先の値を取得 内部処理時間計算 外部処理時間

    計測開始 外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェアとHTTPクライアントで処理時間を計測 ctx ctx
  11. © DMM 39 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 Contextの参照先の値を取得 内部処理時間計算 外部処理時間

    計測開始 外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェアで全体処理時間の計測を開始 ctx ctx
  12. © 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のポインタを生成
  13. © 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を ラップする
  14. © DMM 43 全体処理時間 計測開始 Contextに参照をセット 全体処理時間計測終了 内部処理時間計算 外部処理時間 計測開始

    外部処理時間 計測終了 Contextにセットされた 参照先を更新 ミドルウェア(帰り)で内部処理時間を算出 ctx ctx
  15. © 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に 時間を付与する