はじめに
ここ最近、国内外のテックブログで「マイクロサービスの失敗」というテーマが大きな話題になっています。
実際にマイクロサービスから脱却する企業も増えてきています。
「え? 最新のシステムは全部マイクロサービスにするべきなんじゃないの? モダンシステムはマイクロサービスでしょ」と思うエンジニアの方も多いかもしれません。
システム設計のトレンドとしてここ数年「正義」とされてきたマイクロサービスですが、なぜ今になって一部でマイクロサービスからの脱却の動きになっているのか。
今回はその背景と、実際にマイクロサービスで失敗した有名企業の事例、そして「マイクロサービスの何がそんなに辛いのか」をまとめてみました。
本記事は「マイクロサービス否定」ではなく「無計画な分散化への反省」が論点です。その前提でお読みください。
モノリスとマイクロサービスの違い
まずは基本の復習です。
モノリス(Monolith)
すべての機能(ユーザー管理、決済処理、在庫更新処理など)が 1つの大きなアプリケーション として塊になっている構成です。
ビルドもデプロイも1回で済みますが、一部の改修の影響が全体に波及する可能性があります。
マイクロサービス(Microservices)
機能ごとにアプリケーションを 細かく分割 し、それらをAPI経由で連携させる構成です。
ビルドもデプロイもサービス毎に必要で、理論上は変更影響を局所化しやすい構成です。
これだけ見ると、細かく分かれているマイクロサービスのほうが「拡張しやすそうだし、疎結合でモダンでカッコいい」と感じると思います。実際、数年前までは多くの大企業がこぞってマイクロサービスへ移行していました。
現場のSEが吐露する「マイクロサービス運用のここが辛い」
マイクロサービスは、設計図の上では非常に理想的で美しく見えます。
しかし、いざ開発が始まると、現場のシステムエンジニアには次のような困難が降りかかります。
分散トランザクション(データの整合性)が地獄
モノリスであれば、1つのデータベースの「BEGIN TRANSACTION 〜 COMMIT」で終わる話でした。
しかし、多くのマイクロサービスアーキテクチャでは、サービスごとに独立DB(例えば「ユーザーサービス用DB」「決済サービス用DB」「在庫管理サービス用DB」といった個別DBを定義)を持つため、決済に成功したのに在庫の減算でエラーが起きた場合、 「すでに完了した決済をAPI経由でわざわざ打ち消す処理(補償トランザクション)」を自前で実装 しなければなりません。これがバグの温床になります。
もちろん、Saga Pattern や Outbox Pattern など、分散トランザクション問題を緩和する設計パターンも存在します。
しかし、それらを正しく実装・運用するには高い設計難易度が伴います。
ローカル開発環境が立ち上がらない
「自分のローカルPCで、新機能のデバッグをしたい」と思ったとします。
モノリスならリポジトリを1つクローンして起動するだけというシンプルな構成も多いです。
(巨大モノリスも開発環境地獄だろ! 依存サービス色々あって大変だろ! というツッコミがありそうですが)
しかし、マイクロサービス化が進みすぎると、「Aを動かすためにBとCが必要で、Cを動かすためにDとEが必要…」と連鎖し、デバッグ環境構築に何時間もかかったあげく開発者のローカルPCのメモリが足りずにシャットダウン。
いったい何人のエンジニアが発狂したことか・・・
結果、検証環境サーバーに繋ぎながら開発する羽目になり、開発効率が著しく低下します。
エラーの「分散トレース」で迷子になる
システムで障害が起きた際、エラーログを追うのが非常に困難です。
1つのリクエストが10個のサービスをリレー形式で跨いでいくため、共通の「トレースID」を発行して高度なログ監視基盤をガチガチに組み込まないと、ログを見てのエラー解析どころか 「どこでリクエストが死んだのか」 すら迷宮入りする可能性があります。
実際にマイクロサービスの課題に直面した有名企業の事例
実際にマイクロサービスの課題に直面した企業事例を調べてみました。
1.Amazon Prime Video(アマゾン)
もっとも有名な事例の一つが、Amazon Prime Video の「動画品質監視システム」です。
このシステムでは当初、AWS Lambda や AWS Step Functions を活用した分散型アーキテクチャを採用していました。しかし、大量の映像データを高頻度でサービス間連携する構成だったため、サービス間通信コストやオーケストレーションの複雑化が顕在化しました。
そこでチームは、AWS Lambda や Step Functions による過度な分散処理を見直し、単一プロセス寄りの構成へ再統合しました。
なお、これは Prime Video 全体をモノリスへ戻したわけではなく、特定ワークロードに対するアーキテクチャ最適化の事例です。
その結果、この監視システムにおいて インフラコストを約90%削減 したと報告されています。
※Prime Video Tech Blog の一次ソースは現在公開終了していますが、複数の転載・引用記事で内容を確認できます。
2.Twilio Segment(セグメント)
顧客データプラットフォームを提供するSegment(現Twilio Segment)も、マイクロサービスからモノリスへ統合した代表例としてよく引用されます。
同社は当初、送信先ごとにサービスを分離し、100以上のサービス/リポジトリを運用していました。
しかし、成長とともに運用コストの増大や開発速度の低下といった問題が深刻化しました。
実際に同社は、
“Instead of enabling us to move faster, the small team found themselves mired in exploding complexity.”
(開発を速くするはずが、複雑性の爆発に苦しむようになった)
と述べています。
その後、複数サービスを単一リポジトリ・単一サービスへ統合し、開発効率と運用性を改善しました。
Twilio Segment: Goodbye Microservices: From 100s of problem children to 1 superstar
3.Istio(Service Meshの代表格)
Kubernetes上のマイクロサービス同士の通信を管理するツール(サービスメッシュ)である「Istio」自体も、大きな方向転換をしています。
初期バージョンでは多数の独立コンポーネントに分かれていましたが、インストールが難しい、デバッグしづらいといった問題がユーザーから強く指摘されました。
そこで Istio 1.5 では、多数の制御プレーンコンポーネントを「istiod」という単一バイナリへ統合しました。
これは「運用容易性を優先した統合」の代表例としてよく紹介されます。
Istio: Announcing Istio 1.5
4.楽天
楽天も、巨大システムをマイクロサービス化する過程で多くの苦労を経験した企業として知られています。
同社は、長年運用していた大規模システムを、障害波及範囲の最小化やスケーラビリティ向上を目的として、Kubernetesベースのマイクロサービス構成へ移行しました。
しかし、その過程では、CI/CDの全面見直し、サービス間依存の整理、運用監視設計の複雑化など、多数の課題に直面したと紹介されています。
特に、単に「サービスを分割する」だけでは解決できず、運用設計や開発プロセスそのものの見直しが必要になった点は、多くの企業に共通するマイクロサービスの難しさと言えるでしょう。
CodeZine: 楽天がモノリス→マイクロサービス & オンプレ→クラウドで経験した光と闇
5.aumo(GREE X Tech Blog)
旅行・おでかけメディア「aumo」の開発事例でも、マイクロサービスの難しさと「モジュラーモノリス」の再評価が語られています。
同記事では、Railsベースのシステムにおいて、過度なサービス分割を行うと「分散モノリス化」が起きやすく、結果として認知負荷や運用コストが増加すると指摘されています。
そのため、aumoでは「完全分散」ではなく、
- コードベースは統一
- ドメイン境界だけ厳密化
- モジュール単位で疎結合化
という「モジュラーモノリス」的な設計を採用しているとのことです。
これは、「とにかく全部マイクロサービスに分割する」のではなく、運用現実とのバランスを取った設計事例として非常に参考になります。
GREE X Tech Blog: Railsにおけるモジュラーモノリス導入事例 〜マイクロサービスとの比較と実践〜
「目的」と「手段」を混同しない
これらの事例や運用の辛さから、私たちが学ぶべき一番の教訓は「トレンドだからという理由だけで技術を選ばない」ということです。
モダン技術、流行りのアーキテクチャは、触っていて楽しいですし、挑戦したくなる気持ちはとてもよく分かります。
しかし、システム開発の本来の「目的」は、ユーザーに素早く安定した価値を届けることです。技術はそのための「手段」に過ぎません。
社会人1年目に先輩に口酸っぱく注意された「目的と手段を混同するな!」がまさにここで起こっていました。
最初は疎結合のモジュラーモノリスから始めて、本当に必要になったタイミングで初めて、そこだけを切り離す というのが、あるべきマイクロサービスの形ではないでしょうか。
DB分割まで踏み込むのは簡単なことではないですが、アプリケーションのみにフォーカスし、きちんと設計された疎結合なモジュラーモノリスから、ひとつの機能を切り出すのは現場レベルで許容される難易度ではないかと思います。
(もちろん、その「きちんと設計された疎結合なモジュラーモノリス」を構築すること自体、高い設計力が求められるのですが・・・)
さいごに
「モノリスは古い技術だからダメ、マイクロサービスは新しいから良い」「顧客がマイクロサービスって言っているから」という話ではなく、それぞれの メリットとデメリットを天秤にかけ、自分たちのチームやシステムの規模に合っているか をきちんと考えること。
それこそが、エンジニアに求められる大切な視点なのだと思います。