Monzoのマイクロサービスの数は、この数年で100から1,600にまで増加し、さらに増え続けている。マイクロサービスは責務が増えると分割され、密結合すると統合される。エンジニアはコードジェネレーションを使って自身のサービスを生成し、デプロイし、スケールアップし、監視することができる。
Monzo(訳注:英国のオンライン銀行)のエンジニアであるMatt Heath、Suhail Patel両氏がQCon London 2020で、Monzoのバンキングインフラストラクチャの構築、運用、メンテナンスについて講演した。
その中でPatel氏は、新たなマイクロサービスを開発する時に、エンジニアがフィードバックを求める方法について説明した。
当行の文化は非常にフィードバック指向です。解決しようとする問題の概要に技術的ソリューションの提案を加えた提案書をエンジニアが作成し、提出します。提案書は社内全体に公開されます。これにより、提案されたインターフェースセットに対するフィードバックの提供と、広範なコンテキストによる賛同を獲得する機会を得るのです。将来的に入社する技術者に対して優れたドキュメントを提供する、という効果もあります。
マイクロサービスによってMonzoが獲得した最大のメリットは組織的な柔軟性だ、とPetel氏は言う。
当行のサービスは、理解の容易なサイズに細分化されています。サービスの所有権は明確に定義されていますが、企業の目標に基づいて流動的にもなります。過去2年間で、Monzoは大きく成長しました。その結果、既存チームの構造や新チームの編成に大きな変化が起きているのです。
InfoQは今回、MonzoのバックエンドエンジニアであるSuhail Patel氏にインタビューして、Monzoがマイクロサービスを使用する理由、マイクロサービスの形式、多数のマイクロサービスを伴うシステムの管理、マイクロサービスによって得たメリットなどについて聞くことができた。
InfoQ: Monzoがマイクロサービスの採用を決定した理由を教えてください。
Suhail Patel: 当行のミッションは、世界最高の企業銀行口座と当座銀行口座を構築し続けることです。設立当初より、当行のテクノロジ選択は、その目標を促進するものである必要がありました。他所で大規模システムのスケールアップを経験した後だったため、当行では最初からマイクロサービスを選択していました。
Monzo Betaがローンチされた時には、前払い口座(pre-paid account)をサポートする100近いマイクロサービスが存在していました。2017年に銀行免許を取得し、完全な当座預金サービスを構築しました。それ以来、多数のユーザ向け機能を開発し、さまざまな支払いネットワークとのインテグレーション(その多くは社内開発です)を行っています。この豊富な機能セットを提供するために、サービスの数は1,600以上にまで増えました。
InfoQ: Monzoでは、マイクロサービスをどのように利用しているのでしょう?
Patel: マイクロサービスにビジネスロジックの薄いレイヤを配置し、バックにあるコアライブラリと抽象化を各サービスが共有する、という形式です。サービスの99パーセントがGo言語で記述されており、当行のコアKubernetesプラットフォーム上で運用されています。
ツーリングでは、標準化を大きく取り入れています。サービスのエンジニアリング方法の違いを最小限にして、強化したトップレベルライブラリのセットを活用することがその目標です。エンジニアがサービスを記述する上で必要とするものはすべてツールによって生成し、潜在的なバグの原因をチェックする静的解析をコンパイル時に行っています。共有ライブラリにフックすることで、ほとんどの場合において、サービス特有のコードを1行も変更することなく、プラットフォームチームによる基盤実装の改善やマイグレーションの実施が可能になっています。
InfoQ: マイクロサービスが単一責務であることや、インターフェースが十分に定義されていることは、どのように保証しているのでしょうか?
Patel: プラットフォーム側としては、マイクロサービスのビルディングブロックがシームレスに相互接続できるように、ガイダンスやツールを提供しています。最終的なインターフェースバウンダリの判断は、サービスの実装と状態メンテナンスを担当するチーム内で行います。
当行のプロダクトは常に変わっているので、その時点で100パーセント正確なインターフェースというものはありません。責務が拡大したマイクロサービスが分割されたり、あるいは密結合や相互依存性のあるマイクロサービスの統合が提案がされることもよくあります。こういった変更を行う場合にも、技術的な問題はほとんどありません。
InfoQ: 多数のマイクロサービスで構成されているシステムを、どのように管理しているのでしょうか?
Patel: 全体としての目標は、エンジニアが自身で記述してサポートするマイクロサービスの構造に自身のドメインをオーガナイズする上で、可能な限り自律的であるようにすることです。プラットフォームチームである私たちは、それをサポートする知識や資料、ツーリングを提供します。
マイクロサービスにはそれぞれ関連付けられた所有チームがあって、サービスの正常性に責任を持っています。サービスの所有者が移動する場合には、警告やコードレビューといった他の責務も同じように、自動的に移動することになります。
当行のプラットフォームは、基本的にセルフサービスです。エンジニアはプラットフォームを運用するチームとインターフェースする必要なく、サービスの生成、デプロイ、スケールアップ、監視を行うことができます。これを実現するために、KubernetesやPrometheusといった実証済のインフラストラクチャを、多種多様な独自ツールを使って運用し、基盤として使用しています。
InfoQ: コードジェネレーションはどのように使っているのでしょうか、それによってどのようなメリットがありましたか?
Patel: コードジェネレーションはサービス導入の直後から使用しています。ジェネレータは、サービスのスケルトン構造を生成するために使用します。必要なフォルダ構造をすべて生成し、定型的なコードを記述してくれます。RPCサーバなどの構成やメトリクスの設定なども適切に行ってくれるので、
エンジニアがRPCインターフェースを定義して、さらにそのRPC呼び出しの実装スタブをコードジェネレータで生成することが可能になっています。エンジニアの認知オーバーヘッドが少し低減することで、累積的に、ビジネス選択への集中と選択のパラドックスの低減が実現しているのです。
逸脱の必要なケースもありますが、まったく構いません。この構造をすべてのサービスに指示することが目的ではないからです。逸脱には相応の文書化と正当化、および知見の伝達が必要である、という知識を前提として、エンジニアに選択を任せています。
InfoQ: チーム間の標準化は何を対象に、どのように行っているのですか?
Patel: チームに対して、特定のツールの利用を義務付けてはいませんが、説得力があって必要十分な(batteries-included)サービス構造と、関連するライブラリやツールを提供しています。これがトップレベルのライブラリのセットであって、すべてのサービスで使用されているものです。これらのライブラリがRPCトランスポート層やキューシステムとのインタラクション、リッチメトリクス、分散ロッキング、集中型ロギングなど、多くの部分をカプセル化しています。
標準ツールの使用を促進する上では、ドキュメントも大きな役割を果たします。新たにシステムを開発しているのであれば、当行の最も重要なサービスで使用されているデザインパターンとコードを活用できるということで、証明済のパターンやツールを使用するためのインセンティブが高まります。ドキュメントの明確化という点では、ナレッジベースチュートリアルや行内Stack Overflow Wikiなどに多くの労力を割いています。
InfoQ: マイクロサービスを導入することによって得たメリットと教訓は、どのようなものでしたか?
Patel: Monzo全体のサービスの大部分は、同じコード構造とツーリングを採用しています。このため、変更時の認知オーバーヘッドが低くなっています。行内で新たなチームに参加する場合に、まったく違うスタックを学ぶ必要がないことから、移動性が向上するというメリットもあります。チーム内のエンジニアが変更を提案するのは自由ですし、サービスの開発、デプロイメント、スケールアップはすべて任せられています。
サービスが所定の方法から外れなければならないようなシチュエーションもあります。実際にマシンラーニングのサービスでは、そのような例がいくつかありました。この種のサービスはマシンラーニングにPythonライブラリを多用するため、それらをGoで再実装するコストが正当化できないことが少なくないのです。そうであっても、適切なインターフェースバウンダリを定義すれば、同じRPCレイヤを使用し、プラットフォームの同じメリットを活用することで、プラットフォームの大部分は再実装する必要がなくなります。
複雑性をブレークダウンして、理解の容易な小さなチャンクにすることで、それぞれのサービスはよりシンプルに、より理解しやすいものになります。反復的な変更をすることで、開発速度を向上し、リスクを低減することが可能になるのです。