本記事の目的
本記事の目的は,マイクロサービスを採用する前に考えたいことを可能な限り網羅し,「事前に知っておけばマイクロサービスを採用しなかった」,或いは「もっと上手くマイクロサービスを採用できた」といった悲しい思いをする人を一人でも減らすことにある.マイクロサービスの個々の懸案事項を語る記事はたくさんあるが,本記事では個別事項を深堀する前に,まずは入口として考えるべきこと全体を俯瞰することを目指す.個別事項の詳細は,参考リンクや下記に紹介する書籍を参考にされたい.
どのようにして考えた項目か
筆者が以前マイクロサービス移行を開発者として経験した際,前もってもっと考えておけばよかったのでは?と思ったことをベースに,著書「モノリスからマイクロサービスへ」(※以下,書籍)を読みながら整理したものを,6つの観点で13項目にまとめたものである.書籍では触れられておらず筆者の経験にもとづく観点を一部含むが,ここに挙げられる項目は絶対ではなく,あくまで筆者の整理の中で必要と感じた事柄であること留意されたい.
目次
システム全体としてみたときの複雑化・肥大化に耐えうるか考える
① 細分化によるパフォーマンスや信頼性のトレードオフを認識する
② コストの上昇を認識する
横串を挿し全体の整合性を早めに取る
③ 監視やロギングの基盤を早期に整える
④ エラーハンドリングの方法を事前に合意する
⑤ 最低限守るべき品質基準やセキュリティ項目を明確化する
移行戦略を考える
⑥ ドメインやデータベースを分割可能か検討する
⑦ 既存システムの部分的・段階的な移行計画を立てる
必要な人員を考える
⑧ 既存システムの開発者をマイクロサービスの設計・開発に巻き込む
⑨ 中長期でマイクロサービスを支える人員を維持できるか考える
マイクロサービス化に付随する周辺技術を確認する
⑩ CI/CDによる自動化されたパイプラインを導入する
⑪ リポジトリ戦略を策定する
⑫ フロントエンドの分割を検討する
基本に立ち返る
⑬ 上記を踏まえて,マイクロサービスの採用が本当に妥当かもう一度考える
詳細
システム全体としてみたときの複雑化・肥大化に耐えうるか考える
① 細分化によるパフォーマンスや信頼性のトレードオフを認識する
- マイクロサービスは銀の弾丸ではない,モノリスよりも劣る点や制御が難しい点あり
- パフォーマンス観点
- サービス間でネットワーク越しに通信することで,レイテンシが増加する傾向
- 信頼性の観点
- 通信を挟むことでパケロスのリスクも増大する傾向
- 各サービスの複雑なトリガが絡み合い,微妙なタイミングが噛み合わないことによる不具合の発生可能性
(書籍では「ミステリー小説の殺人事件」と表現) - 複雑で理解容易性が低いことによるバグの混入の可能性
- 上記のパケロスやタイミング問題を回避する追加対策による複雑化とイタチごっこ
- サービス間の繋がりが見えにくいことによる理解の阻害など
② コストの上昇を認識する
- 単一のマシンで充足していたプロセスを複数のマシンに分割することによるコスト増加
- 水平スケールによるコスト上昇の可能性
- 各々のマイクロサービスを開発・運用するための人員確保
横串を挿し全体の整合性を早めに取る
③ 監視やロギングの基盤を早期に整える
- トラブルシューティングの際などに,各分散マシン上のログを個別に収集・解析は困難
- ログの集約を推奨
- リクエストごとに複数のマイクロサービスをまたいだ相関の確保(分散トレーシング)
- 後追いで全サービスに仕組み徹底させるのは大変なため,初期に合意しておきたい
④ エラーハンドリングの方法を事前に合意する
- 通信の失敗や「ミステリー小説の殺人事件」などを前提とし,リトライやタイムアウトの設計が必要
- サービスの呼び出しチェーンでエラーを扱う難しさ(下記記事参照)
- 冪等性の担保
- 後追いで全サービスにポリシを徹底させると大変なため,初期に合意しておきたい
⑤ 最低限守るべき品質基準やセキュリティ項目を明確化する
- ルールベースの項目等ある程度の規律
- 監査対応項目など避けては通れないもの
- コード品質
- 複数のチームの裁量に依りすぎると,バラバラな品質のサービスが立ち上がる可能性
- テスト方法
- 特にE2Eテストはサービスをまたぎスコープが大きくなるため不安定になりやすく複雑
- 破壊的変更(単独サービスのデプロイがシステム全体として動かなくなる問題)への対策
- 後方互換性の確保
- もしものときのロールバック方法の検討
- 後追いで全サービスに徹底させると大変なため,初期に合意しておきたい
- 破壊的変更対策とロールバックをおざなりにすると,複数サービス一括デプロイする羽目になり,結局「分散モノリス」になってしまう
移行戦略を考える
⑥ ドメインやデータベースを分割可能か検討する
- マイクロサービスがマイクロサービスたるためには,各サービスが独立してデプロイ可能である必要
- マイクロサービスの境界を定義するのに,ドメイン駆動設計が有用
- サービス間でのデータベースの共有は結合を生み,デプロイ独立性の担保が難しくなるため避けるべき.データはサービス内に隠蔽することを推奨
- DB分割の際に,分散トランザクションに対処する必要
- 対処例: sagaパターンによる結果整合性の確保
- サービスの分解に失敗すると「分散モノリス」と呼ばれる悲惨なパターンに陥る可能性
- 分散して管理されているが,実際には一括してデプロイが必要で,調整等に多大な労力が必要なパターン
- マイクロサービスとモノリスの悪いとこ取り
⑦ 既存システムの部分的・段階的な移行計画を立てる
- ビッグバンリライトではなく,段階的な移行が書籍では推奨
- マイクロサービス移行が正しく進んでいるか小さく試して検査が必要
- e.g. ストラングラーフィグパターンによる移行が有用
- アプリケーションの前段にファサードを設け,新旧システムを併存させながら,マイクロサービスへの移行完了となった機能から順にルーティングを切り替えていくパターン
必要な人員を考える
⑧ 既存システムの開発者をマイクロサービスの設計・開発に巻き込む
- 特に移行専任チームを作る場合,既存システムのノウハウを引き継ぐ必要
- 可能であれば,既存システムのメンバを移行チームに入れると,多少スムーズに進むと思われる
⑨ 中長期でマイクロサービスを支える人員を維持できるか考える
- サービスとチームの関係(所有権のスケール)
- 逆コンウェイの法則に従い,理想的にはマイクロサービスごとにチームを割り当てるのがスムーズ
- 現実的には,1つのチームで複数のサービスを受け持つ可能性
- 一方で,サービスの共同所有はコミュニケーションコストの増加の原因
- 前提としてサービスのあるべき姿や方向性がチームを跨いで共有されている必要
- 誰も責任を取らないサービスが生まれるリスク
- 組織体制の変更の可能性
- 各チームが担当サービスをオーナシップをもって開発から運用まで一貫して継続するのがスムーズ
- 現実的には開発者の入れ替わりや,組織的判断によるチームの組み換え可能性
- マイクロサービスのメリットとしてサービスごとに柔軟に技術選定可能な点が挙げられるが,もしものとき引継ぎ可能な技術にとどめる方が現実的かもしれない
マイクロサービス化に付随する周辺技術を確認する
⑩ CI/CDによる自動化されたパイプラインを導入する
- サービス数が増えると,手元で多くのサービスを立ち上げる必要性があり,開発・デプロイ・管理のコストが激増
- ある一定の規模までは手動プロセスで事足りても,どこかで破綻の可能性
- サービス一括構築ツールで誤魔化す案を思いつくかもしれないが,元も子もない
- ある程度スケールしたタイミングで立ち止まって,プロセスを自動化する前提で構えることを推奨
⑪ リポジトリ戦略を策定する
- Polyrepoは簡単に導入できる一方で,その分断がシステム全体の理解を阻害したり,管理の煩雑化を助長
- ある程度のスケールを想定する場合,Monorepoの導入も検討されたい
- ツールの導入・習熟・運用が発生
⑫ フロントエンドの分割を検討する
- バックエンドのマイクロサービス化や移行戦略において,フロントエンドが足手まといになる可能性
- UI分割やマイクロフロントエンドを用いて,フロントエンドを分割することを検討してもよい
基本に立ち返る
⑬ 上記を踏まえて,マイクロサービスの採用が本当に妥当かもう一度考える
- マイクロサービスは銀の弾丸ではない,多数の痛みを伴う
- マイクロサービス導入が目的化していないか
- マイクロサービスの代替手段はないか(モジュラーモノリスなど)
- マイクロサービスに適したプロダクトか
- システム規模,プロダクトフェーズ,ドメインの境界が明確さ
- マイクロサービスに耐えうる組織か
- 人員,チーム体制,スキルセット,文化
まとめ
マイクロサービスの採用にあたっては,事前に多くのことを考慮する必要がある.ただ小さく分割して実装を進めればよいというわけではない.
書籍でも述べられているように,段階的に移行し,導入・移行が成功しているか適宜検査できるように準備しておく必要がある.