このページでは、大容量データを 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 に書き込まれるスプリットが多くなると、commit のレイテンシとオーバーヘッドが増加します。各ランダム行が異なるスプリットに属する可能性があり、複数のスプリットが関係する可能性が高くなるためです。最悪のシナリオでは、各書き込みが Spanner インスタンスのすべてのスプリットに関係します。前に説明したように、書き込みスループットは、より多くのスプリットが関係すると低下します。
パーティショニングなしの一括読み込み
1 つの 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 あたりのミューテーション数に関する Spanner の制限を超えるリスクがあります。
セカンダリ インデックスのガイドライン
データベースにセカンダリ インデックスがある場合は、データベース スキーマへのそのインデックスの追加を、テーブルデータの読み込み前に行うか、後に行うかを選択する必要があります。
データが読み込まれる前にインデックスを追加すると、スキーマの変更をすぐに完了できます。ただし、インデックスに影響する各書き込みではインデックスの更新が必要になるため、処理に時間がかかります。データの読み込みが完了すると、すべてのインデックスが配置された状態でデータベースがすぐに使用できるようになります。テーブルとそのインデックスを同時に作成するには、新しいテーブルと新しいインデックスの DDL 文を 1 つのリクエストで Spanner に送信します。
データの読み込み後にインデックスを追加すると、書き込みが効率的になります。ただし、インデックスのバックフィルごとにスキーマの変更には長時間を要する可能性があります。 データベースは完全には使用できず、すべてのスキーマ変更が完了するまで、クエリはインデックスを使用できません。データベースでは引き続き書き込みとクエリを実行できますが、速度は低下します。
データを読み込む前に、ビジネス アプリケーションにとって重要なインデックスを追加することをおすすめします。ミッション クリティカルでないすべてのインデックスについては、データの移行後に追加します。
スループットのテストと測定
スループットは予測が困難な場合があります。最終読み込みを実行する前に、一括読み込みの戦略をテストすることをおすすめします。パーティショニングとパフォーマンスのモニタリングを使用した詳細な例については、データ読み込みスループットの最大化をご覧ください。
既存データベースへの一括読み込みを定期的に行う際のベスト プラクティス
データは含むがセカンダリ インデックスがない既存のデータベースを更新する場合にも、このトピックのベスト プラクティスが当てはまります。
セカンダリ インデックスがある場合、同様の手順で一定のパフォーマンスが得られますが、パフォーマンスは、トランザクションに関係するスプリットの平均数に依存します。スループットが低すぎる場合は、次の方法を試してください。
- 各 commit に含まれるミューテーションの数を減らします。これにより、スループットが向上する場合があります。
- アップロードの容量が更新対象テーブルの現在の合計サイズよりも大きい場合は、いったんセカンダリ インデックスを削除し、アップロードが完了した後で追加し直してください。この手順は通常は必要ありませんが、スループットが向上する場合があります。