すべてのエンジニアリングチームは、悲鳴を上げることなく成長できるシステムを望んでいます。トラフィックはスムーズに上昇し、サーバーは静かに稼働し、収益は着実に増えていく……そんな光景を思い描きます。しかし、現実は非情です。バイラルなマーケティングキャンペーンによってユーザーの波が押し寄せ、データベースがロックされ、誰かが午前3時に必死になってサービスを再起動している……そんな事態が起こります。その時、つい道具のせいにしたくなります。「もっとコア数が必要だった」「もっと速いディスクが必要だった」「別のキャッシュレイヤーが必要だった」と自分に言い聞かせます。しかし、成長はハードウェアから生まれるのではありません。構造から生まれるのです。もし土台が重みを分散できなければ、新しいユーザーが増えるたびに、それは勝利ではなく負債となります。

壊れた土台をツールで救うことはできない

100個のクラウドインスタンスを立ち上げ、地理的リージョン間にロードバランサーを追加し、すべての静的アセットをグローバルなコンテンツ配信ネットワーク(CDN)でキャッシュすることもできるでしょう。これらは力を増幅させる要素(フォース・マルチプライヤー)です。しかし、ゼロに何を掛けても結果はゼロです。依存関係が複雑に絡み合ったモノリシックなアプリケーションは、その下にどれほど強力なハードウェアが控えていようとも、自らの重みに押しつぶされてしまいます。

商品カタログ、決済処理、ユーザー認証がすべて単一のコードベースに存在するオンラインショップを想像してみてください。チェックアウトの流れが遅くなると、サイト全体が低速になります。ログインページがもたつき、ブラウジング体験が悪化します。ボトルネックだけをスケールさせることはできず、他のすべてを同時にスケールさせなければなりません。それはコストがかかり、非効率で、脆弱です。ユーザーが瞬時に読み込まれるべきページを待っている間に、誰も恩恵を受けないコンピューティングパワーに対して料金を支払うことになります。

アーキテクチャこそが、この罠に対する答えです。アーキテクチャとは、ツールが助けになるか、それとも邪魔になるかを決定する、目に見えない骨組みなのです。

堅牢なアーキテクチャが真に意味するもの

堅牢なアーキテクチャとは、単に「責務をどこに持たせるか」という計画に過ぎません。それは、早い段階で厄介な問いを投げかけます。一つの部品が壊れたらどうなるか? レコメンデーションエンジンに触れることなく、請求ロジックを変更できるか? アプリケーションの一角でトラフィックが急増しても、システムの他の部分は正常に動作し続けられるか? これらの問いは、プログラミング言語やフレームワーク、クラウドプロバイダーの選択よりもはるかに重要です。

優れたアーキテクチャは、考えを変えるための余地を与えてくれます。明確な境界線を定義することで、あるチームの実験が別のチームの本番環境のワークロードを不安定にさせないようにします。また、障害を「予期せぬ事態」ではなく「通常の動作条件」として扱います。障害を念頭に置いて設計すれば、壊れやすい「ガラスの家」を作るのではなく、しなやかに受け流す構造を作り始めることができるのです。

実践的なパターンとしてのマイクロサービス

そのような構造を実現する実践的な方法の一つが、アプリケーションをマイクロサービスに分割することです。一つの巨大なコードベースにする代わりに、アプリを小さなパーツに分けます。各パーツは特定の仕事を担当します。決済サービスはトランザクションを処理し、在庫サービスは在庫を追跡し、通知サービスはメールやテキストメッセージを送信します。これらは、直接的なメモリへのアクセスや共有データベースのテーブルではなく、定義されたインターフェースを通じて通信します。

この分離により、技術面でも組織面でも、真の機動力(マニューバビリティ)が生まれます。

システム全体を壊さずに小さなパーツを更新する

サービスが小さく特化していれば、連鎖的な障害のリスクを冒すことなく、一つのパーツにパッチを当てることができます。チームが配送計算アルゴリズムのバグを発見した場合、そのサービスだけを修正して個別にデプロイできます。アプリケーションの残りの部分は動き続けます。ユーザーは引き続き商品を閲覧し、ログインし、カートにアイテムを追加できます。単一の変更による影響範囲(ブラスト・ラジアス)は極めて小さく抑えられます。これに対し、モノリスでは、ヘルパー関数内のタイポ一つで、チェックアウト、登録、レポート機能がすべて一度に壊れてしまう可能性があることを考えてみてください。

トラフィック増加時に特定の機能をスケールさせる

アプリケーション全体のトラフィックが常に均一であることはありません。フラッシュセールの最中、注文パイプラインは負荷がかかっている一方で、コンテンツ管理システムはほとんどアイドル状態かもしれません。密結合なシステムでは、すべてをスケールさせるか、さもなくば何もスケールさせられないかのどちらかです。マイクロサービスを使えば、リソースをピンポイントで投入できます。チェックアウトサービスのインスタンスを増やし、商品カタログは通常の規模のまま稼働させます。新製品の発売時には、検索インデックスは落ち着いていても、画像処理ワーカーが数千ものサムネイル作成をキューに溜めているかもしれません。画像ワーカーのためだけに検索クラスターを拡張する必要はありません。ユーザーが恩恵を感じる場所に資金を投じることができ、システムはプレッシャーの下でもレスポンスを維持できます。

長時間のダウンタイムなしで新しいコードをデプロイする

小規模なサービスは、メンテナンスウィンドウを不要にするようなデプロイパターンを可能にします。ローリングデプロイメントを使用すれば、一部のインスタンスに新しいコードをプッシュしている間、残りのインスタンスでトラフィックの処理を継続できます。エラー率を監視し、何かおかしいと感じたら、数秒でリクエストを前のバージョンに戻すことができます。ブルーグリーンデプロイメントを使用すれば、完全に新しい環境を立ち上げて検証し、最小限のリスクでトラフィックを切り替えることができます。誰かが手動でデータベースのマイグレーションを実行している間、システムを数時間も停止させる必要はありません。

新機能をより速く構築する

大規模なコードベースは慎重さを生みます。たった一つの変更であっても、無関係な数千行のロジックを理解し、数時間かかる回帰テストを行い、ロケットの打ち上げのようなデプロイスケジュールに従わなければなりません。小規模なサービスは、そのような恐怖を取り除いてくれます。チームは、熟知しているサービスの数百行を修正するだけで、新しい機能を構築できます。彼らは、コミット、テスト、リリースを同じ日に行うことができます。その速度は加速度的に増していきます。サービスの責任範囲が明確に境界付けられていれば、チーム同士が互いの作業を妨げることはなくなります。各チームが自らのドメインをエンドツーエンドで所有できるようになるのです。

独立性が大規模な混乱を防ぐ

各サービスは独立して動作します。その独立性は単なる組織上の利便性ではなく、構造的な保険です。レコメンデーションエンジンがダウンしても、ストアは製品を販売し続けられるべきです。分析パイプラインが不正なイベントによって停止しても、ログインサービスはユーザーの認証を継続できるべきです。一つの障害がシステム全体の停止へと連鎖しないよう、サービス間にサーキットブレーカーとフォールバックパスを設計します。システムは、継ぎ目から崩壊することなく負荷を吸収できるため、ユーザーの増加とともに成長していくことができます。

注意:盲目的に分割してはいけない

これらは、初日からコードベースを断片化すべきだという意味ではありません。マイクロサービスには明確な境界が必要です。もしチームが、あるドメインがどこで終わり、別のドメインがどこから始まるのかをまだ理解していないのであれば、分散システムではなく「分散された混乱状態」を作り出すことになります。コードの複雑さを運用上の複雑さと引き換えにすることになり、突然、数十ものログストリームにわたるネットワークレイテンシ、分散トランザクション、リトライストーム、そしてオブザーバビリティの管理に追われることになります。チェックアウトの遅延をデバッグするということは、4つのネットワークホップと3つの異なるデータストアにわたって単一のリクエストを追跡することを意味するようになるかもしれません。

もしチームにそのコストを支払う準備ができていないのであれば、解決策が問題そのものよりも厄介なものになってしまいます。時には、モジュラーモノリスから始める方が賢明な判断となることもあります。たとえ一緒にデプロイされるとしても、コードベース内では決済ロジックを在庫ロジックから分離しておきます。内部APIを使用して境界を強制し、同じエンジン内であってもデータベーススキーマを分離します。それらの境界が安定し、トラフィックパターンがオーバーヘッドを正当化できるようになった段階で、サービスとして切り出します。アーキテクチャとは、ブログ記事を読んだからといって一晩で築かれた壁ではなく、意図的に設けられた一連の扉であるべきです。

意図を持って始める

堅牢なアーキテクチャとは、5年後のトラフィックを予測することではありません。自分自身に選択肢を与えることです。Webアプリを成長させるためにツールだけに頼ることはできませんが、圧力が強まる前に思考によって困難を回避することはできます。責任の境界を尊重してください。自らの運命を自らコントロールできる、小さく集中したパーツを構築してください。全体を壊すことなく迅速に動けるよう、チームに自律性を与えてください。堅牢なアーキテクチャから始めれば、サイトが炎上している最中にコアロジックを書き直す必要がなくなるため、後々の時間と労力を節約できます。

真の教訓

スケーラビリティは、成長が訪れたときに後付けする機能ではありません。それは、システム内で責任がどのように流れるかについて、早い段階で行った選択の自然な結果です。正しい継ぎ目を選んでください。障害を隔離してください。負荷がかかっている部分をスケールさせ、正常に動作している部分はそのままにしておきます。そうすれば、後から追加するツールが、実際に支えとなる強固な基盤の上で機能するようになるでしょう。