Firebase Realtime Database でパフォーマンスを最適化し、データをスケーリングする最善の方法は、データを複数の Realtime Database インスタンスに分割すること(データベース シャーディング)です。シャーディングを行うと、ロード バランシングやパフォーマンスの最適化だけでなく、個々のデータベース インスタンスに適用される上限を超えてスケールできる柔軟性が得られます。
データをシャーディングすべき状況
以下のいずれかのシナリオで Realtime Database を使用している場合は、複数のデータベースにデータをシャーディングすることをおすすめします。
- 単一のデータベース インスタンスに適用される同時接続数 200,000、1 秒あたり 1,000 回の書き込みオペレーション、またはその他の上限を超えてスケールする必要がある場合。
- 独立した複数のデータセットがあり、パフォーマンスを最適化する必要がある場合(たとえば、個別の独立したユーザー グループにサービスを提供するチャットアプリ)。
- 複数のデータベース間で負荷を分散して稼働率を向上させ、単一のデータベース インスタンスの過負荷リスクを軽減する必要がある場合。
データをシャーディングする方法
データをシャーディングする手順は次のとおりです(詳細は後述します)。
- アプリ固有のニーズに応じて、複数のデータベースにデータをマッピングします。
- 複数のデータベース インスタンスを作成します。
- データセットごとに必要な Realtime Database インスタンスに接続するようにアプリを構成します。
データをマッピングする
データを複数のデータベースにマッピングする場合は、以下の条件を満たすようにしてください。
- 各クエリが、単一のデータベース インスタンスに対してのみ実行されること。Realtime Database は、複数のデータベース インスタンスに対するクエリに対応していません。
- 複数のデータベース インスタンス間でデータの共有や重複が発生しないこと(または共有や重複を最小限に抑えること)。
- いかなる時点でも、各アプリ インスタンスが 1 つのデータベースだけに接続していること。
データをマッピングする際には、次の戦略を使うことをおすすめします。
「マスター シャード」を作成する
データが複数のデータベース インスタンス間にどのように格納されているかを示すマップを保存します。これにより、接続するクライアントに対応するデータベース インスタンスをプログラムによって検索できます。ただし、この戦略では、必要なときに特定のデータベース インスタンスに直接接続するよりも、オーバーヘッドが増える可能性があることに注意してください。
データをカテゴリ別またはお客様別にバケット化する
サイロ化し、ユーザータイプまたはデータ型でグループ化したデータベース インスタンスにデータを保存します。たとえば、複数の組織にサービスを提供するチャットアプリを構築する場合は、組織ごとにデータベース インスタンスを作成し、すべてのチャットデータを固有のデータベース インスタンスに格納できます。
この場合、組織 A と組織 B はデータを共有せず、データベース内に重複データは発生せず、単一のデータベース インスタンスに対してのみクエリが実行されます。さらに、各組織のユーザーがチャットアプリを使用するときは、各自の組織のデータベースだけに接続します。
この場合、あらかじめ複数のデータベース インスタンスを作成しておき、組織の ID を使用して、そのデータベース インスタンスにチームをマッピングできます。たとえば、組織 A を Realtime Database A にマッピングします。
アプリのデータをマッピングする方法は、各自のユースケースによって異なりますが、前述の条件や戦略は、データに適した方法を定義するのに役立ちます。
複数の Realtime Database インスタンスを作成する
Blaze 料金プランをご利用の場合は、同じ Firebase プロジェクト内に最大 1,000 個のデータベース インスタンスを作成できます。
- Firebase コンソールで、[開発] > [データベース] セクションの [データ] タブに移動します。
- [Realtime Database] セクションのメニューから [新しいデータベースを作成] を選択します。
- データベース参照とセキュリティ ルールをカスタマイズして、[OK] をクリックします。
このプロセスを繰り返して、必要なだけデータベース インスタンスを作成します。各データベース インスタンスには独自の Firebase Realtime Database セキュリティ ルールセットがあり、データへのアクセスを細かく調整できます。
Firebase コンソールで、または Realtime Database Management REST API を使用して、データベース インスタンスを作成し、管理できます。
各インスタンスの Realtime Database セキュリティ ルールを編集してデプロイする
Realtime Database セキュリティ ルールにより、プロジェクト内の各データベース インスタンスへの適切なアクセスが許可されていることを確認します。各データベースには独自のルールセットがあり、ルールの編集やデプロイは Firebase コンソールから行います。また、デプロイ ターゲットに対する Firebase CLI を使用してルールの編集やデプロイを行うこともできます。
Firebase コンソールでルールを編集してデプロイするには:
- [開発] > [データベース] セクションの [ルール] タブに移動します。
- 編集するデータベースを選択し、ルールを変更します。
Firebase CLI からルールを編集してデプロイするには:
- データベース インスタンスのルールファイル(
foo.rules.json
など)内のルールを変更します。 - デプロイ ターゲットを作成してデプロイし、同じルールファイルを使用するデータベースを関連付けます。次に例を示します。
firebase target:apply database main my-db-1 my-db-2
firebase target:apply database other my-other-db-3
デプロイ ターゲットを使用して
firebase.json
構成ファイルを更新します。{ "database": [ {"target": "main", "rules": "foo.rules.json"}, {"target": "other", "rules": "bar.rules.json"} ] }
deploy コマンドを実行します。
firebase deploy
- データベース インスタンスのルールファイル(
常に同じ場所からルールを編集してデプロイするようにしてください。Firebase CLI からルールをデプロイすると、Firebase コンソールで行った編集がオーバーライドされます。また、Firebase コンソールで直接ルールを編集すると、Firebase CLI でデプロイした最新の変更がオーバーライドされます。
アプリを複数のデータベース インスタンスに接続する
セカンダリ データベース インスタンスに保存されているデータにアクセスするには、データベース参照を使用します。特定のデータベース インスタンスの参照は URL またはアプリで取得できます。URL を指定しないと、アプリのデフォルト データベース インスタンスの参照を取得することになります。
ウェブ向けのモジュラー API
import { initializeApp } from "firebase/app"; import { getDatabase } from "firebase/database"; const app1 = initializeApp({ databaseURL: "https://testapp-1234-1.firebaseio.com" }); const app2 = initializeApp({ databaseURL: "https://testapp-1234-2.firebaseio.com" }, 'app2'); // Get the default database instance for an app1 const database1 = getDatabase(app1); // Get a database instance for app2 const database2 = getDatabase(app2);
ウェブ向けの名前空間付き API
const app1 = firebase.initializeApp({ databaseURL: "https://testapp-1234-1.firebaseio.com" }); const app2 = firebase.initializeApp({ databaseURL: "https://testapp-1234-2.firebaseio.com" }, 'app2'); // Get the default database instance for an app1 var database1 = firebase.database(); // Get a database instance for app2 var database2 = firebase.database(app2);
Swift
// Get the default database instance for an appvar ref: DatabaseReference! ref = Database.database().reference()// URL でセカンダリ データベース インスタンスを取得する var ref: DatabaseReference! ref = Database.database("https://testapp-1234.firebaseio.com").reference()
Objective-C
// Get the default database instance for an app@property (strong, nonatomic) FIRDatabaseReference *ref; self.ref = [[FIRDatabase database] reference];// URL でセカンダリ データベース インスタンスを取得する @property (strong, nonatomic) FIRDatabaseReference *ref; self.ref = [[FIRDatabase databaseWithURL:@"https://testapp-1234.firebaseio.com"] reference];
Kotlin+KTX
// Get the default database instance for an app val primary = Firebase.database.reference // Get a secondary database instance by URL val secondary = Firebase.database("https://testapp-1234.firebaseio.com").reference
Java
// Get the default database instance for an app DatabaseReference primary = FirebaseDatabase.getInstance() .getReference(); // Get a secondary database instance by URL DatabaseReference secondary = FirebaseDatabase.getInstance("https://testapp-1234.firebaseio.com") .getReference();
Firebase CLI を使用する場合のインスタンスを指定する
Firebase CLI コマンドを適用する Firebase Realtime Database を指定するには、--instance
オプションを使用します。たとえば、my-example-shard.firebaseio.com
というデータベース インスタンスのプロファイラを実行するには、次のコマンドを使用します。
firebase database:profile --instance "my-example-shard"
各データベースの接続を最適化する
セッション中に各クライアントが複数のデータベースに接続する必要がある場合は、必要なときだけ各データベース インスタンスに接続することで、同時接続数を減らすことができます。
アドバイスが必要な場合
複数のデータベース インスタンスにわたってデータをシャーディングする処理の詳細については、Slack チャンネルか Stack Overflow から Firebase のエキスパートにお問い合わせください。