スタディサプリ/Quipper Product Meetup #3 ~SREチームが取り組むマイクロサービス化に向けたDevOps開発事例~に参加してきた。
スタディサプリ/Quipper Product Meetup #3 ~SREチームが取り組むマイクロサービス化に向けたDevOps開発事例~
参加してきたので簡易まとめ。
https://techplay.jp/event/737389
当日の公式レポート
Observability in StudySapuri
Yuya Takeyama
スタディサプリ、何故マイクロサービス化するのか
GrobalのQuipperとコードベースが共通→ある国での変更が別の国の機能に影響しうる
各国の各チームがそれぞれ独立して開発サイクル回したい
マイクロサービス化の現状
Kubernetesでマイクロサービス基盤を整えた
HerokuやDeisで動かしていたものを載せ替え
マイクロなサービスはまだ10もない状況
大きな二つの流れ
マイクロサービスとしてサービスを切り出す
新しい機能をマイクロサービスとして作る
データ系プロダクト(Python/Flask)など
Observability(可観測性)の大切さ
サービスの状況が外からどれだけ見えるかという性質
マイクロサービスだとより重要
全体のアーキテクチャが複雑なため発生する問題も複雑
正しく分析するために大切
Observability(可観測性)の三要素
Metric
Logging
Tracing
Metric
様々なレイヤに渡る
AWS,Kubernetes Node(EC2/Linux),Kubernetes Pod,Protocolなど
→Datadogで収集
Rubyで動いているサーバが多い
UnicornのPodのワーカーごとのメモリ使用量
Rubyのメモリブロード(断片化)→メモリ増加→プロセスkill→立ち上げ直し・・・
細かいメトリクスはDatadog等が勝手に拾ってくれるわけではない
- Prometheus Exporter
GitHub上などに落ちている
https://prometheus.io/docs/instrumenting/exporters/
- Datadog Autodiscovery
Prometheus Exporterからの収集にも対応
Logging
サービスまたいでログ収集、検索可能
GCPのStackdriver Loggingを収集
標準出力・エラー出力に書くだけで勝手にfluentdで収集
リクエストIDで検索するとエラー探せる
今後の展望
ログフォーマットの統一化
フィールド名の統一
Tracing
複数サービスをまたいだリクエストにおいて、ボトルネックを可視化
まだ活用できていない
Stackdriver Trace検討中
Canary release - フレームワークのアップグレードを安心して進めるためのリリース戦略
Fumiaki Matsushima
本番構成とデプロイについて
アーキテクチャはユーザ別
Git flowでmonorepo上で開発・・・ディレクトリごと別サービス、レポジトリは1つ
各ディレクトリにKubernetes関連ファイルがある
overlaysで差分管理
Build,DeployはCircleCIから
ワークフローは約150ジョブから成る、差分のみ実行
Canary releaseとは
一部のユーザに新機能を先に公開しリスクを減らす
プロセスごと分離
プロセスを2系統上げていないといけない
やらないといけないこと
- 新旧フレームワークでテスト回し、開発が止まらないようにする
アップグレードに関わっていない人の方が多い
開始を停止するわけにいかない:全員に両方でテストが通るコードを書いてもらう
依存する社内gemも2系統で
- 簡単にフレームワークのバージョンが切り替えられるようにする
2種類のライブラリバージョン管理ファイルを持つ
※Ruby特有
- 新旧フレームワーク両方デプロイされるようにする
各ディレクトリ=サービス
シンボリックリンクを貼り、分岐を入れて楽をする
- 割り振るルールを決める
同じユーザには同じ挙動をするべき
問い合わせ対応、再現確認の手間を考えて
ログインしていないユーザの考慮
一度新しいバージョンが使われたら戻ってほしくない
→CookieにCanary release用IDを振る
+環境変数で何%くらいID振るか決める
初めのリクエストは古いほうにいくが割り切った
移行の流れ
0 , 0.1 , 1, 10, 50, 100
ロジック確認のため0は挟んだほうがいい
確率通りか見る
エラー監視
Sentryにフレームワークのバージョンをタグとして付与、
そのタグがついている場合のエラー通知先を分離
リリース時、何が起きたか
本番で問題は起きなかった
ステージングはCanary releaseの割合を高めていた(エラー拾って対処できた)
自動テストがしっかりできていた
改善点
段階リリースに時間がかかり過ぎた
新エラーの判別を楽したい
バージョン依存の問題かどうか?の判断
まとめ
新しいサービスを簡単に足せるようになっていれば
Canary release単純な実装で実現できる
まだまだ俺たちのアップグレードはこれからだ!
gRPC in スタディサプリ ENGLISH
Yuta Kimura
gRPC導入経緯
- 各サービスごとの通信を共通化するため
当初の構成では負荷分散されず・・・
AWSは外部通信に対してはHHTTP/2は対応しているが、
内部通信に対してHTTP/2は対応していない
上記が分かっていたのでCLBのTCPモードで負荷分散していたが、
負荷が増えるにつれて障害につながるレベルの負荷になった
gRPCの負荷分散
プロキシロードバランシング
クライアントサイドロードバランシング
方法検討
利点と難点
- プロキシロードバランシング
クライアント側に手を入れないで実現
ロードバランサ、プロキシの性能に左右される
- クライアントサイドロードバランシング
余計な経路が発生せず高性能
ロードバランシングの実装が各言語に寄ってしまう
実装によって変わるためクライアント側の複雑性が増してしまう
結論
現時点で高性能さはいらない、障害対応優先
既存のコードに手を入れたくなかった
→プロキシロードバランシングを採用
Nginx vs HAProxy vs Envoy
- Nginx
利用実績はあったが事例がなく断念
- HAProxy
検討時点でgRPCのサポートをしていなかった
- Envoy
docが豊富、gRPCのサポートあり
→Front Procy
api前にenvoyが動作するサービスをデプロイ
ELBをenvoyに置き換えるイメージ
問題点
APIの前にCLBはHTTP/2に対応していない
=ELBを使わないとき、クライアント側に対象IP一覧を返す機能が必要
→Amazon ECS Service Discoveryを採用
まとめ
gRPCの負荷分散が最初できていなかったのに問題として取り上げられなかった、のような 技術的負債が生まれてしまっていることはよくある
新しいものを入れるときは影響範囲と切り戻しの範囲を考える
自分が何をしているか共有しやすい形で進めるのがおすすめ。
Scrapbox便利
Envoyはまだまだ新しい!楽しい!
CQRS+ESをKinesis,Spark,RDB,S3でやってみた
Tsubasa Matsukawa
CQRSとは
コマンドクエリ分離原則
更新と参照を分ける考え方
コードがシンプルになる利点がある
※デメリット:設計に工夫が必要
Event Sourcing
イベントを主役とする
State Sourcingでは消えてしまう有用な履歴情報をすべて残せる
Eventをhookに色々な処理が書ける。
※デメリット
イベントの数が多くなると状態を計算する処理のコストが大きい
任意のタイミングでスナップショットを作るなどして回避
データの持ち方
学習ログをRDBに保存していた
都度集計し、クライアントが欲しい形に整形
→データが増えて重くなってきた
学習者のグループを管理する要件が追加され、集計が重くなってしまった
ロジックが複雑になった
embulkを使ってデータ変換してみた
CQRS+ES,Kinesis,Spark,RDB,S3の構成へ
Sparkとは
リアルタイム処理に強い
EMRとは
マネージドクラスタプラットフォーム。
大規模分散処理基盤を手軽に立ち上げ&実行できる
→これらを組み合わせて効率よくCQRS+ESをやる
- 保存場所
コマンド、クエリはRDB
EventはS3
S3は高性能かつコスパが良く、AWSの他サービスと連携しやすくていい!
データの伝播
状態を都度更新するので計算コストがかからない(データ量に応じて重くならない)
- Spark
全イベントを利用した状態の復元、スナップショット作成
S3からデータ取得しやすくした
切り換えも安心安全
並行稼働させ、データに問題がないと確認できたら切り替える
まとめ
イベントはS3に置くのがオススメ