今年も通らなかったので、Kaigi on Rails 2024 でRejectされたプロポーザル置いておきます
posted at 2024-08-16 23:36:00 +0900 by kinoppyd
何
タイトルの通り、今年のKaigi on Rails 2024 のプロポーザルも採択されなかったので、誰かの役に立てばと思い公開しておきます。
CFP
Abstract
事業に新機能を足していく時、マルチアプリケーションという方法を選択することがあると思います。マルチアプリケーションは、マイクロサービスとは違いアプリケーションごとの独立自治性を高め、コードベースも各自のドメインに関するもののみに関心を向けられる、メリットの多い開発手法です。一方で、マルチアプリケーションではデータベースが分離されており、他のアプリケーションとのやり取りにはAPIを用意して通信する必要があります。このトークでは、事業の急激な変化により十分なデータ通信方法を確立しないまま巨大になってしまったアプリケーション群をつなぐため、GraphQL Federationという技術を選択し運用しているお話をします。加えて、GraphQL Federationだけでは解決できなかった横断的検索に対するDatabase Federationという解決策に関してもお話します。
For Review Committee
Details
大まかなトークの概要として、GraphQLをつかったバックエンドサーバー間のデータ通信に関するお話をします。一般的にGraphQLはフロントエンドがバックエンドと通信する際の技術という認識があると思いますが、スキーマによるデータの取捨選択や型の管理などは、バックエンド間での通信でも十分に通用します。マイクロサービスとは違い、完全に独立した別物の複数アプリケーション間で、データの構造や型を守りつつ、相互に安全に通信する手段として、GraphQLとそのオープンな拡張であるGraphQL Federationという技術を選択した話をします。完全なるモノリスではなく、複数のアプリケーションが動いている環境であれば、どこでも応用できるお話です。
SmartHRのアーキテクチャは、祖業である労務管理のRailsアプリに加え、多数のRailsアプリがそれぞれ完全独立で動いています。例えば、労務領域では文書配布や年末調整、書類申請はそれぞれ完全に独立した、Google Cloud上のVPCすら分割されたアプリです。さらに、昨今のタレントマネジメント領域も評価、分析、サーベイなど多数のRailsアプリが動いています。これらはいずれも独立したデータベース、独立したネットワークで動いています。連携のためにOAuth認可によるユーザーの識別、および労務アプリケーションを中心としたREST APIでのスター型ネットワークを構築しています。
労務アプリを中心としたスター型ネットワークは、ある程度の規模まではうまく動いていました。各チームが独自に労務アプリに専用のAPIを作成し、データを取得してくることでそれぞれの機能を十分に動かすことができました。しかし、さらに規模が大きくなってくると、様々な問題が出てきました。その一つが、労務以外のアプリ間でのデータ連携が必要となってきたことです。これまでは独立して機能していれば十分でしたが、現在ではタレントマネジメントアプリに入力したデータを、他のタレントマネジメントアプリから取得したいという要望が多くなりました。短期的に見ると、タレントマネジメントアプリ同士でRESTを作成しあいデータを交換すれば良いように思えますが、ネットワークがフルメッシュに移行してしまい管理が難しくなります。また、データスキーマを適切に管理設定できないと、アプリケーション間で取得しているデータに差異が出てきて、長期的にデータ連携が破綻する可能性も高いです。そのため、SmartHRの従業員情報というエンティティを定義したうえで、適切にデータを共有し合う必要がありました。
技術選定の段階では、API Gatewayを使ったRESTの集合や、GraphQL Federation、Datalakeの作成、データ同期でフルコピーなどの案がありましたが、以下の理由でGraphQL Federationが選択され、その中でも有力だったApollo Fedeartionを採用しました。
- データスキーマが定義されており、それをチームで管理できる
- 社内にGraphQLを使ったバックエンド通信の前例がある
- GraphQLは必要なフィールドのみを指定するので、トラフィックの節約ができる
- データ同期やDatalakeなどに対して、失敗した際にすぐに切り戻しが可能
Apollo Federation自体は公開仕様であり、またRustで実装されたルーターもOSSのため自由に使用ができます。そのため、この構成を作ってみること自体は、かなり簡単に真似ができますし、十分に運用に足るものです。一方で、Apolloはエンタープライズ向け機能として、GraphOSというスキーマやトラフィック、エラー監視を管理するSaaSも提供しています。このSaaSの使い勝手は、OpenAPIなどでRESTのスキーマを管理するよりも良さそうに思えたので、導入をしました。
Apollo Federationを導入した結果、複数のアプリケーション間でデータのやり取りが行われるようになり、連携を前提とした新しいアプリケーションもリリースされています。スキーマの管理も各チームの自治性を保持しつつ、全体のデザインとして違和感のないようガイドラインを整備しながら日々拡張を行っています。現在まで大きなトラブルもなく、非常に安定したデータ連携用のシステムが動いています。
一方で、いくつものアプリケーションが参加するGraphQLのスキーマを作成するうえで、いくつか問題も発生しました。例えば、アプリケーションによってデータの時系列に対する考え方が違うという問題があります。労務アプリケーションは、バイテンポラルモデルを使った厳密な時系列と履歴を管理していますが、それ以外のアプリは大体がその時点でのデータを保持しているにとどまっています。そのため、従業員の履歴をどう表現するかという問題があり、この問題は現在も継続中です。他にも、必ずしもスキーマに落とし込めるデータばかりではないという問題もありました。サーベイなどは、内容をユーザーが独自にカスタマイズできるため、それを汎用的に表現しようとするとPDFみたいなデータ構造になってしまいます。そのため、特定のプリセットを使ったデータのみを現在は提供していますが、今後はユーザーが作ったサーベイの提供なども求められており、苦慮しています。
また他の問題として、アプリケーションをまたいだ検索の構築が非常に難易度が高いこともわかりました。「AかつB」を検索するには、2つのグラフがそれぞれ検索した結果の和を得ればよいですが、「AかつBではない」を2つのグラフの検索結果から得ることは難しいです。なぜならば、アプリケーションごとに同期している従業員の情報に違いがあるので、「Aである」と「Bではない」はそれぞれ違う全集合の演算になってしまい、「Aである」から「Bではない」を単純に除算することができないためです。この話は複雑なので、採択された場合はスライドで詳細に説明します。
この検索の問題を解決するべく、ほぼアトミックに複数のDBをクエリする方針で解決をはかりました。ツールにはTrinoというデータベースフェデレーションツールを使い、すべてのデータベースを検索グラフが直接参照しています。それによって検索は改善されましたが、現在はSQLの生成が複雑になっているという課題が残っています。検索改善のお話も、時間があれば少し話そうと思います。
Pitch
GraphQLは、一般的にはフロントエンド用の技術で、バックエンド間でのデータ連携に使用しているという例は国内では非常に珍しいと思います。またその中でも、GraphQL Federation という選択をした企業は更に少ないと思います。SmartHRでは、NetflixやRippling、国内だとMoney Forwardなどの先行事例を調査し技術選定を行いました。あまり国内で耳馴染みのない技術をそれなりの規模で運用している話を共有することで、マルチプロダクト戦略をとっている会社の選択肢としてGraphQL Federationを増やし、検討できるようになれば良いなと思っています。また、いま成長の真っ只中に居て、アプリケーションをどのように拡張していくかを悩んでいる方々にとっても、マルチプロダクトという選択肢を後押しできる話になると考えています。複数のアプリケーション間の通信方法としての知識の引き出しを増やします。
Speaker Information
kinoppyd SmartHRで働くプログラマ、うどんよりそばがすき。