マルチテナントアーキテクチャの設計のポイント
「マルチテナントアーキテクチャとデータ設計について、今後の開発や運用に役立つ情報を持って帰ってもらいたい」
冒頭でこう語り、和田氏のセッションは始まった。
エイトレッドではいくつかのプロダクトやサービスを展開している。そのうちの一つに、ワークフローシステムが標準搭載されたマルチテナント型クラウドアプリケーションプラットフォーム「AWP」がある。同サービスは入力フォームと承認ルートを定義すれば、容易に旅費精算や稟議書などのワークフローが完成するというサービスである。「回した書類の集計や、CSV、PDFへの出力、Webhook機能を使った外部システムとの連携なども行える。業務システム基盤として汎用的に使えるようになっている」(和田氏)
同サービスはエンドユーザーに直接ではなく、SIerやパッケージベンダーなどにマルチテナント形式でサービス提供するという形を採用している。
AWPは、どのようなアーキテクチャで実現しているのか。アプリケーション層については、共有するかしないかというところがポイントになると言う。同社サービスではロードバランサで処理を振り分けつつ資源を共有する形を採用している。「ここで注意すべき点はセッション情報をサーバ間で共有できるようにデータベースに外出しして管理する、もしくはセッションレプリケーションを行う必要があることだ」と和田氏は指摘する。同サービスの場合はRedisでセッションを管理している。
次にデータベースについては、「種類も増えているので、それに合わせて考えていく必要があるが、基本的には次の4パターンに分類できる」と和田氏。第一が完全にサーバレベルで分離するパターン。第二はある程度のテナント数ごとにサーバを分けつつ、さらにその中でデータベースやスキーマレベルで論理的に分離するというパターン。第三はサーバの内部で論理的に分離するパターン。第四がテーブルも共有して、レコードの属性でテナントを識別するというパターンである。
「数字が大きいほど効率がよいが、私たちのサービスはメインのMongoDBは現状パターン3で、パターン2にも移行できるような準備をしているところ」と和田氏は説明する。またMariaDBもパターン3で、Elasticsearchはパターン2となっていると言う。
同サービスのアーキテクチャはすべてAWSの上に構築。図のとおりだが、アプリケーションサーバは6台用意。DBはMongoDBとElasticsearchがそれぞれ3台構成、MariaDBとRedisはマネージドサービスを利用している。
![図1 AWPのアーキテクチャ概要](http://cz-cdn.shoeisha.jp/static/images/article/11647/11647_p14.jpg)
アプリケーションサーバの役割は、APIとバッチ処理の実行と静的コンテンツの配信。アプリケーションはコンテナ化し、Amazon Elastic Compute Cloud(EC2)を使って運用している。「ポイントは、3台はほとんどのAPIの処理とコンテンツ配信を行い、残りの3台でバッチの実行や一部の重いAPIを振り分けて実行する形にしていること」と和田氏は説明する。ただ、最近はバッチ用のサーバの処理が厳しくなってきたので、重たい処理はさらに専用のサーバを用意してそちらに振り分けつつ、それぞれのサーバ台数を増やしながらスケールアウトさせていくことを検討していると言う。
続いて、MongoDBについて。MongoDBでは、ほぼすべてのデータを格納している。今年からAWSからもマネージドサービスが提供されているが、「今のところ、移行する予定はない」と和田氏は語る。テナントのデータ分離方法については、データベース名で分離していると言う。またMongoDBにはシャーディングというデータの分散を実現する機能もあるが、方式がそぐわなかったため、使用せずに運用していると言う。そのため自前でデータの分散を考えていく必要がある。同社では、近い将来、ある程度のテナント数ごとにサーバを用意する形、先述したパターン3からパターン2に移行することを検討していると言う。
Elasticsarchの役割は全文検索や集計。「マネージドサービスもあったが、利用したい機能が使えないような設定になっているため、自前でEC2上に3台構成で構築している」(和田氏)
ただこれに関しては「正直ちょっと失敗した」と思っていると言う。現状は安定して稼働しているが、当初、JavaVMが定期的に謎のクラッシュをするという挙動に悩まされたと言う。「Javaのバージョンを入れ替えたりしてなんとか安定したが、これから利用される方は、マネージドサービス利用されることをお勧めする」と和田氏は語る。
データの分離方法は、RDBでいうテーブルに該当するインデックス名でテナントを識別して分離。Elasticsearchのシャーディングの機能を活用し、データ分割やレプリケーション、サーバ追加した時のデータ再配置などを行っていると言う。
最後にMariaDBとRedisは先述したようにマネージドサービスを活用している。MariaDBはトランザクションが必要となるデータの格納、Redisはセッション情報やキャッシュのために利用している。
データの分離について、MariaDBはテーブル名で、Redisはキャッシュに関してのみキーにテナントの識別子を入れて分離している。こちらもMongoDB同様、将来的にはサーバ台数を増やしていこうと計画していると言う。さらに和田氏はクライアントからのリクエストがどのテナントから来たものか、識別する方法についても紹介。「URLドメインで識別するか、セッション情報に持たせて識別するかの2択になるが、これから開発する場合は、1つめのドメインで識別するパターンをお勧めする」と語る。特に複数テナントへの同時ログイン、特定テナントだけ別サーバに処理を振り分けたい場合はお勧めだと言う。