このページでは、大容量データを Spanner に効率よく一括読み込みするためのガイドラインを説明します。
Spanner にデータを一括で読み込む方法はいくつかあります。
- データ操作言語(DML)を使用して行を挿入する。
- ミューテーションを使用して行を挿入する。
- Dataflow コネクタを使用してデータをインポートする。
- Avro ファイルを使用してデータベースをインポートする。
- CSV 形式のデータをインポートする。
Google Cloud CLI を使用して行を挿入することもできますが、一括読み込みに gcloud CLI を使用することはおすすめしません。
一括読み込みのパフォーマンス ガイドライン
一括読み込みのパフォーマンスを最適化するには、パーティショニングを最大限に活用して、ワーカータスク間でデータの書き込みを分散します。
Spanner は負荷ベースの分割を使用して、インスタンスのコンピューティング リソース全体にデータ負荷を均等に分散します。負荷の高い状態が数分続くと、Spanner は行間にスプリットの境界を設定します。一般に、データの負荷が適切に分散されている場合、スキーマ設計と一括読み込みのベスト プラクティスに従うと、インスタンスで使用可能な CPU リソースが飽和するまで、書き込みスループットは数分ごとに倍増します。
主キーによるデータの分割
Spanner は、テーブルを小さな範囲に自動的にパーティション分割します。行の主キーにより、その行がどのパーティションに配置されるかが決まります。
一括読み込みの書き込みスループットを最適化するには、次のパターンになるようにデータを主キーで分割します。
- 各パーティションに、主キー列で決定された連続した行範囲が含まれる。
- 各 commit に、1 つのパーティションのデータのみが含まれる。
パーティションの数は、Spanner インスタンスのノード数の 10 倍にすることをおすすめします。以下の方法でパーティションに行を割り当てます。
- 主キーでデータを並べ替えます。
- データを 10 ×(ノード数)個の同じサイズのパーティションに分割します。
- 各パーティションにそれぞれワーカータスクを作成して割り当てます。ワーカータスクはアプリケーション内で作成されます。これは Spanner の機能ではありません。
このパターンにより、負荷が大きい場合、一括書き込み全体のスループットの最大値がノードごとに 10~20 MB/秒になります。
データを読み込みながら、Spanner はスプリットを作成して更新し、インスタンスのノード間で負荷を分散します。このプロセスにおいてスループットが一時的に低下する場合があります。
例
3 つのノードを持つリージョン構成があるとします。この構成の非インターリーブ テーブルには 90,000 行あるため、主キーは 1〜90,000 の範囲になります。
- 行数: 90,000 行
- ノード数: 3
- パーティション数: 10 × 3 = 30
- パーティションあたりの行数: 90,000 ÷ 30 = 3,000
最初のパーティションには 1 から 3,000 までのキー範囲、2 番目のパーティションには 3,001 から 6,000 までのキー範囲が含まれています。同様の範囲指定を行っていくと、30 番目のパーティションのキー範囲は、87,001 〜 90,000 になります(大規模なテーブルでは連続したキーを使用しないでください。この例はデモ用です)。
各ワーカータスクは単一のパーティションに書き込みを送信します。各パーティション内では、主キーによって行を順番に書き込みます。主キーを基に、行をランダムに書き込む場合でも、比較的高いスループットが得られます。テスト実行を測定することで、データセットに最大のパフォーマンスをもたらすアプローチがわかります。
パーティションを使わない場合
commit 内でランダムな行を書き込むと、commit 内に連続した行セットを書き込むよりも時間がかかることがあります。また、異なるパーティションのデータにアクセスする可能性があります。コミットに書き込まれるスプリットが増えると、サーバー間の調整が増えるため、commit のレイテンシとオーバーヘッドが増加します。各ランダム行が異なるスプリットに属する可能性があり、複数のスプリットが関係する可能性が高くなるためです。最悪のシナリオでは、各書き込みが Spanner インスタンスのすべてのスプリットに関係します。前述のように、書き込みスループットが低下するのは、スプリット数が増加した場合です。
パーティショニングなしの一括読み込み
連続した行セットを commit に書き込むと、ランダムな行を書き込むよりも高速になる場合があります。ランダムな行には、異なるパーティションのデータが含まれている可能性もあります。
より多くのパーティションが commit に書き込まれると、サーバー間での調整が必要になり、commit のレイテンシとオーバーヘッドが増加します。
各ランダム行が異なるパーティションに属する可能性があるため、複数のパーティションが関係する可能性があります。最悪のシナリオでは、各書き込みが Spanner インスタンスのすべてのパーティションに関係します。前述のように、書き込みスループットが低下するのは、パーティションが増加した場合です。
過負荷を回避する
Spanner が処理できる以上の書き込みリクエストが送信される場合があります。Spanner は、トランザクションを中止することにより過負荷に対処します。これをプッシュバックと呼びます。書き込み専用トランザクションの場合、Spanner は自動的にトランザクションを再試行します。この場合、プッシュバックによりレイテンシが高くなります。高負荷が続くと、プッシュバックは 1 分間続くことがあります。非常に高い負荷の場合、プッシュバックが数分間続くことさえあります。プッシュバックを避けるには、書き込みリクエストを調整して CPU 使用率を相応の範囲内に抑える必要があります。または、CPU 使用率が制限内に収まるようにノードの数を増やすこともできます。
1 MB~5 MB のミューテーションを一度に commit
書き込みが大きくても小さくても、Spanner に書き込むたびにオーバーヘッドが生じます。スループットを最大化するには、1 回の書き込みで格納されるデータ容量を最大まで増やします。書き込みが大きいほど、書き込みごとのオーバーヘッドの比率が低くなります。適切な方法は各 commit で数百単位の行を変更することです。比較的大きな行を書き込むときは、commit のサイズを 1 MB~5 MB にすると、通常最適なパフォーマンスが得られます。小さい値やインデックス付きの値を書き込むときは、通常、1 回の commit で数百行まで書き込むことをおすすめします。 commit のサイズや行数とは関係なく、1 回の commit あたりのミューテーションは 80,000 までという制限に注意してください。最適なパフォーマンスを見いだすには、スループットをテストして測定する必要があります。
5 MB 超の commit や数百行を超える commit では特別なメリットはなく、commit サイズと commit あたりのミューテーション数に関する Spanner の制限を超えるリスクがあります。
セカンダリ インデックスのガイドライン
データベースにセカンダリ インデックスがある場合は、データベース スキーマへのそのインデックスの追加を、テーブルデータの読み込み前に行うか、後に行うかを選択する必要があります。
データの読み込み前にインデックスを追加すると、スキーマ変更をすぐに完了できます。ただし、インデックスに影響する書き込みごとにインデックスの更新も必要になるため、時間がかかります。データの読み込みが完了すると、すべてのインデックスが配置されたデータベースをすぐに使用できます。テーブルとそのインデックスを同時に作成するには、新しいテーブルと新しいインデックスの DDL 文を 1 つのリクエストで Spanner に送信します。
データの読み込み後にインデックスを追加すると、書き込みが効率的になります。ただし、インデックスのバックフィルごとにスキーマの変更には長時間を要する可能性があります。 データベースは完全には使用できず、スキーマの変更がすべて完了するまで、クエリでインデックスを使用できません。データベースは書き込みとクエリを処理できますが、速度は遅くなります。
データを読み込む前に、ビジネス アプリケーションに不可欠なインデックスを追加することをおすすめします。重要なインデックス以外は、データの移行後に追加します。
スループットのテストと測定
スループットは予測が困難な場合があります。最終読み込みを実行する前に、一括読み込みの戦略をテストすることをおすすめします。パーティショニングとパフォーマンスのモニタリングを使用した詳細な例については、データ読み込みスループットの最大化をご覧ください。
既存データベースへの一括読み込みを定期的に行う際のベスト プラクティス
データは含むがセカンダリ インデックスがない既存のデータベースを更新する場合にも、このドキュメントのベスト プラクティスが当てはまります。
セカンダリ インデックスがある場合、同様の手順で一定のパフォーマンスが得られますが、パフォーマンスは、トランザクションに関係するスプリットの平均数に依存します。スループットが低すぎる場合は、次の方法を試してください。
- 各 commit に含まれるミューテーションの数を減らします。これにより、スループットが向上する場合があります。
- アップロードの容量が更新対象テーブルの現在の合計サイズよりも大きい場合は、いったんセカンダリ インデックスを削除し、アップロードが完了した後で追加し直してください。この手順は通常は必要ありませんが、スループットが向上する場合があります。