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
Goを活用したサービス開発・運用の話
Search
sasaki
July 20, 2021
Programming
1.8k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Goを活用したサービス開発・運用の話
sasaki
July 20, 2021
More Decks by sasaki
See All by sasaki
コンテナをGoで作る
kuwabarakuwabara
0
220
Other Decks in Programming
See All in Programming
Composerを使ったサプライチェーン攻撃の様子を眺めてみる #phpstudy
o0h
PRO
2
240
A2UI という光を覗いてみる
satohjohn
1
120
AI時代のUIはどこへ行く?その2!
yusukebe
20
7k
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
150
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
490
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
560
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
180
New "Type" system on PicoRuby
pocke
1
780
Claspは野良GASの夢をみるか
takter00
0
180
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
230
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
130
Contextとはなにか
chiroruxx
0
260
Featured
See All Featured
Practical Orchestrator
shlominoach
191
11k
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
390
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Skip the Path - Find Your Career Trail
mkilby
1
140
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
YesSQL, Process and Tooling at Scale
rocio
174
15k
How to Grow Your eCommerce with AI & Automation
katarinadahlin
PRO
1
200
Information Architects: The Missing Link in Design Systems
soysaucechin
0
960
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
エンジニアに許された特別な時間の終わり
watany
107
250k
HDC tutorial
michielstock
2
700
Transcript
Goを活用した サービス開発・運用の話 DMM.go #3 DMM.com 佐々木勝春 2021-07-21
自己紹介 名前:佐々木勝春 略歴: 2017年4月 一般社団法人DMMアカデミーに入社 2019年4月 DMM.comに転籍 | プラットフォーム事業部 2021年7月現在
レビューリプレイス、通知配信&DMMポイントクラブ 余暇:落語(立川流)、映画、ラジオ、 …、 カカオ72% 2
今回お話する内容 1:monorepo&共通アーキテクチャによる複数サービス開発の話 2:安定的なサービス運用のための継続的なモニタリング (現在も模索しながら改善中です!) 3
現在運用中のサービスについて PFでありながらToC要素のあるサービスを作っているのが特徴的です 4
運用中のサービス1: DMMポイントクラブ https://lp.pointclub.dmm.com/ 5
運用中のサービス2: 通知配信サービス https://notification.dmm.com/ ↑共通ヘッダーのベルアイコン 6
開発業務内容 ・サービスの開発・運用(PRD/DesignDocの作成) ・施策の立案、実施&検証&振り返り ・定量・定性分析(データ、ユーザーの声、SNS、...) ・外部チームとの連携 ... 「事業のための開発」 引用: https://www.irasutoya.com/2020/03/blog-post_74.html 7
効率的なサービス運営を行っていくために ・開発の工数をできるだけ削減して効率よく開発していきたい ・モニタリングをしっかりと行って障害の防止、障害発生後の素早いリカバリーを実現し たい。 ・インフラリソースの最適化も継続的見ていきたい。 8
今回お話する内容 1:monorepo&共通アーキテクチャによる複数サービス開発の話 2:安定的なサービス運用のための継続的なモニタリング 9
インフラアーキテクチャ 10
11
ポイントクラブが提供する機能群概要 ・Client(Nativeアプリ)への機能提供→API ・管理系(お知らせ登録・Push通知の配信)→バッチ データ ストア API バッチ 参照・登録 登録 Native
アプリ 管理 追加実装部分 12
通知配信が提供する機能群概要 ・Client(通知一覧・通知のステータス取得)→API ・ユーザーセグメント毎の通知情報の登録→バッチ データ ストア API バッチ 参照 登録 Web
Front 管理 追加実装部分 管理機能はサービスと同じリソー スを扱って一部の処理を共通し て使える ↑ 共通化部分はできれば再 利用したい 13
monorepoを利用した既存リソースの活用 https://speakerdeck.com/ymatsuwitter/cloud-native-and-monorepo?slide=20 今回は主にこの観点から → 14
+α: 既存インフラ環境の有効活用 ・バッチもAPIと同じネットワーク ・ECS Fargateの構成で構築する ことでインフラ構築工数削減(cliコ マンドとして実装する方針に) (これに加えて短時間の定期実行の処理は Lambdaで実 行してるものもあります
) 15
ソースコードアーキテクチャ 16
コードアーキテクチャ概要 ui http query usecase infra domain query: ・外部API依存のもの ・ui層用の表示用(CQRSを参考に参照用モデルとしてドメインオブジェクトとは別に定義
) ポイントクラブと通知配信の両サービスで利用 →アーキテクチャを共通化することで学習コストの削減、仕様さえ把握してい ればすぐに開発に着手できる cli ・関心の分離→ドメインロジックに集中 ・goではinterfaceと構造体を用いたDIの実装 17
ディレクトリ構成 ・main関数のファイルを cmd/配下の/apiと/batchで分離 ・app/ui層以下が/batch/とhttp/で分離 ・usecase層以降はapiとbatchで同じディレクトリ apiとbatchで共通のメソッド(主にinfra層)を利用できる 18
バッチ実装に利用しているライブラリ https://github.com/spf13/cobra 特徴 ・サブコマンド型のCLIツールの作成 ・POSIX準拠のフラグ機能を提供(long型とshort型共に) ・アプリケーションの雛形を作るための機能も提供 ・多段のネストのサブコマンドを作れる ・helpフラグやmapページの自動生成と柔軟なカスタマイズ性 ... 詳細は公式リポジトリを参考ください
19
cobraの選定理由 ・標準ライブラリ(flagパッケージなど)だけでcliを作ることもできるが、なるべく実装の工 数を減らしたい ・cobraはcliのサブコマンド型を作りたいという今回の要件にマッチ ・今回は利用ケースが限定的→どのフレームワークを使っても実現できそう では あった(豊富な機能や採用実績からcobraを作用) 20
app/cmd/batch/main.go package main func main() { ... prepareNotificationCmd := batch.NewPreparePushCmd(pushHandler)
batch.RootCmd.AddCommand(prepareNotificationCmd) if err := batch.RootCmd.ExecuteContext(ctx); err != nil { logger.Write(ctx, logger.LevelError, "エラーが発生しました。", err) os.Exit(1) } os.Exit(0) } main関数内でルートコマンドにサブコマンドを追加 & エラーハンドリング(エラー状況に応じてステータスコードを返却 ) 21
app/ui/batch/root.go package batch import ( "github.com/spf13/cobra" ) // RootCmd :
ルートコマンド var RootCmd = &cobra.Command{ Use: "pointclub-batch", Run: func(cmd *cobra.Command, args []string) { _ = cmd.Help() }, } main関数で利用するrootコマンドを初期化 22
app/ui/batch/notification.go① package batch // Notification : お知らせ通知のためのハンドラー type Notification interface
{ Prepare(cmd *cobra.Command, args []string) error } type notification struct { u usecase.Notification } // NewNotification : お知らせ通知ハンドラーの生成 func NewNotification(u usecase.Notification) Notification { return ¬ification{ u: u, } } cliのhandlerのインターフェースと new関数を定義(apiと同じ構成) ↑サブコマンドで実際に呼び出す関数 23
app/ui/batch/notification.go② package batch // NewPrepareNotificationCmd : お知らせ通知内容を用意するコマンド func NewPrepareNotificationCmd(n Notification)
*cobra.Command { return &cobra.Command{ Use: "prepare-notification", Args: cobra.ExactArgs(1), Short: "お知らせ通知内容を用意(dynamoDBにインサート)する", RunE: func(cmd *cobra.Command, args []string) error { return n.Prepare(cmd, args) }, } } ・サブコマンドを初期化 ・この後紹介するhandlerのメソッドをここでコール 24
app/ui/batch/notification.go③ package batch // NewPrepareNotificationCmd : お知らせ通知内容を用意するコマンド func NewPrepareNotificationCmd(n Notification)
*cobra.Command { ... } // Prepare : お知らせ通知内容を用意 func (n notification) Prepare(cmd *cobra.Command, args []string) error { targetUser := args[0] err := n.u.Prepare(cmd.Context(), targetUser) if err != nil { return fmt.Errorf("お知らせ通知内容の用意に失敗しました。: %w", err) } return nil } ・handlerのメソッドを定義 ・ここでusecase層以降のメソッドをコール ←apiと同じ構成 25
その他、API実装に関して フレームワーク 選定理由 ポイントクラブ Goa ドキュメントとGoを乖離させないため https://speakerdeck.com/yyh_gl/develop-api-server-by-goa 通知配信 echo ・レビューリプレイスの際に利用経験あり
・薄いフレームワークが良かった ・ドキュメントに関しては今回はクライアントはほぼ自分達だけ だったので問題なかった 参考:技術選定に関して https://inside.dmm.com/entry/2019/02/28/technology-selection 26
まとめ1 monorepo&共通アーキテクチャによる開発の効率化 ・monorepoによるメソッドの共通利用により開発工数の削減 ・複数サービスで同一アーキテクチャを採用することによる学習コスト・開発コストの削減 +インフラ構成の共通化やフレームワークやライブラリの利用による開発工数の削減 27
今回お話する内容 1:モノレポ&共通アーキテクチャによる開発の話 2:安定的なサービス運用のための継続的なモニタリング 28
2:安定的なサービス運用のための継続的なモニタリング ・安定的なサービス運用をしていきたい ・初期MVPも後も継続的に施策の実施、機能追加のリリースをしていきたい ・アクセス増減によるサーバー、データストアのスペックの見直し 29
モニタリング導入による効果例 ・実際のに負荷とリソースの使用状況に応じて APIのコンテナ数削減によりインフラ費用のコスト 最適化 ・メモリリークの検知 30
モニタリングにSaaSのDatadogを利用 Datadog のインテグレーションを使用して、 DevOps スタック全体のメトリクスとイ ベントをシームレスに集約します。 ・インテグレーション ・ダッシュボード ・ログ管理/アラート ・APM
・Continuous Profiler ・ネットワークモニタリング ・Syntheticモニタリング ・リアルユーザーモニタリング ... https://www.datadoghq.com/ja/ DMMPFの標準のモニタリングツールとしても Datadogを採用しています 31
Datadog ・様々な言語に対応 C#,Go, Java,JavaScript, Node, PHP, Python, Ruby, Rust… (利用機能により対応言語は変わります
) ・充実したドキュメント ・頻繁な機能追加・アップデート https://www.datadoghq.com/ja/blog/ https://docs.datadoghq.com/ja/ 32
Datadogのモニタリング活用例(go関連) ・APM ・継続的なProfiling 33
Datadogのモニタリング活用例(go関連) ・APM ・継続的なProfiling 34
APM ↓タグで絞り込み検索ができる コードレベルの可視性で根本原因を素早く特定 35 https://docs.datadoghq.com/ja/tracing/visualization/
APM実装コード① main関数内でAPMトレース開始と終了の処理をコール package main func main() { // APM トレース開始
apm.StartTrace() defer apm.StopTrace() ... } 36
APM実装コード② package apm // StartTrace : トレースを開始 func StartTrace() {
tracer.Start( tracer.WithServiceName("pointclub-api"), tracer.WithGlobalTag("service", "pointclub-api"), tracer.WithGlobalTag("env", os.Getenv("APP_ENV")), ) } // StopTrace : トレースを終了 func StopTrace() { tracer.Stop() } 37
APM実装コード③ トレースしたい任意の関数でspanの開始処理をコール package foo func Foo(ctx context.Context, hoge Hoge) {
span, ctx := apm.StartTraceFromContext(ctx) defer span.Finish() ... } 38
APM実装コード④ span開始の関数 package apm // Span : スパン type Span
tracer.Span // StartTraceFromContext : スパンを開始 func StartTraceFromContext(ctx context.Context) (Span, context.Context) { return tracer.StartSpanFromContext(ctx, getFuncName(2)) } 39
Datadogのモニタリング活用例(go関連) ・APM ・継続的なProfiling 40
・最小限の負荷で本番環境全体のパフォーマンスをコードレベルで分析 →コードのボトルネックを素早く見つける ・全てのスタックトレースを1つの管理画面で可視化する ・リリースversion間の比較による継続的なパフォーマンス傾向の分析 継続的なProfiling 41
goの標準ライブラリ pprofとの違い ・リリースバージョンごとの比較が標準できる ・分散トレースとの相関関係を理解する ・httpサーバーにエンドポイントを差し込まなくていいので実装が楽(特にフレームワーク利用時) https://golang.org/pkg/net/http/pprof/ その他クラウドインフラ系サービスも提供 https://cloud.google.com/profiler/docs/about-profiler/?hl=ja&refresh=1 https://aws.amazon.com/jp/blogs/news/investigating-performance-issues-with-amazon-cod eguru-profiler/
42
継続的なProfiling cmd/batch/main.go (import文省略) package main func main() { // profilerを開始
err := profiler.Start( profiler.WithService("pointclub-api"), profiler.WithEnv(os.Getenv("APP_ENV")), profiler.WithProfileTypes( profiler.CPUProfile, profiler.HeapProfile, profiler.GoroutineProfile, ), ) if err != nil { logger.Panic("profilerの開始に失敗しました。 ", err) } defer profiler.Stop() } 参考: https://docs.datadoghq.com/ja/tracing/profiler/ enabling/?code-lang=go 43
継続的なProfiling https://docs.datadoghq.com/ja/tracing/profiler/intro_to_profiling/ 44
継続的なProfiling 項目 データ型 実装レベル 利用用途 メトリクス 時系列データ 利用者側で実装 (メソッド単位、より大きい 単位)
・利用者側で決めた撮り たいデータを取得できる ・前後関係は分からない プロファイル 統計データ・スナップ ショット的 ランタイムレベル (スタックトレースによる 粒度の小さい単位) ・取れるメトリクスは固定 (CPU使用時間、ヒープ サイズ、スレッド数) ・前後関係がわかるので パフォーマンスのボトル ネックを特定しやすい 45 https://logmi.jp/tech/articles/322787
その他Datadogのモニタリング活用例 ・インテグレーション&ダッシュボード整備 インフラストラクチャーから全てのメトリクスとログを収集して、統合システムを全体として 把握することができる。 https://docs.datadoghq.com/ja/getting_started/dashboar ds/ 46
まとめ ・継続的なサービス運用のためにモニタリングにDatadogを活用 ・データストアのパフォーマンス問題の改善 ・APIサーバーのパフォーマンスの改善は引き続きやっていきたい 47
・monorepo&共通アーキテクチャにより共通化の仕組みを活用した開発工数の削減を 解決 ・継続的なモニタリングで安定したサービスの運用の実施 ・失敗して学びながら徐々に改善していってより良いサービスを提供していきたいです まとめ 48