2TB のコレクションをシャード化し、24 時間以内にすべてのシャードにデータを分散する必要がありますか?リシャーディングを活用してデータ移行を加速します。
免責事項: 私は MongoDB の従業員ですが、表明された意見や見解はすべて私自身のものです。
この投稿では、リシャーディングを使用してクラスター内のシャード間でデータを迅速に分散する「リシャードツーシャード」と呼ばれる手法について説明します。
以下について説明します。
- 移行前および移行中の考慮事項。
- より高速なデータ移行を開始、監視、中止する方法。
シャーディングを初めて使用する場合、またはMongoDB が水平方向のスケーラビリティを実現する方法を再確認したい場合は、以下を確認してください。
目次
- バックグラウンド
- リシャードからシャードへの利点は何ですか?
- reshard-to-shard をいつ使用する必要がありますか?
- reshard-to-shard を使用すべきでないのはどのような場合ですか?
- リシャード間の前提条件は何ですか?
- リシャードからシャードへの手法の概要
- リシャードからシャードへの例
- よくある質問
バックグラウンド
コレクションが最初にマルチシャード クラスター上でシャード化されると、バランサーは、シャード間でコレクションを均等に分散するために、最近シャード化されたコレクションを保持するシャードからクラスター内の他のシャードへのデータの移行を開始します。バランサーがデータを移行しているとき、移行が必要なコレクションの数に関係なく、シャードは一度に 1 つの移行のみに参加できます。つまり、3 シャード クラスターでは、一度に 2 つのシャードのみがシャード間でデータを移行できます。内部実行の違いにより、リシャーディングには同じ制限がありません。
リシャーディングはすべてのデータを書き換えることであるため、クラスター内のすべてのシャードに並行してデータを書き込むことができ、スループットが向上し、バランサーが達成できることと比較してシャード間でのデータの移行時間が大幅に短縮されます。リシャーディングでは、アプリケーションが利用できる既存のコレクションを維持しながら、各シャードのバックグラウンドで新しいシャード キーを使用して新しいコレクションが構築されます。すべてのドキュメントが新しいコレクションに複製されると、カットオーバーが発生します。古いシャード キーを持つ既存のコレクションは削除され、リシャーディング操作によって構築された新しいコレクションが優先されます。
リシャードからシャードへの利点は何ですか?
まず、はるかに高速です。リシャーディングを活用することで、お客様は 22.5 時間以内に 3.5 TB のコレクションを 4 つのシャードにシャーディングして分散することができました。バランサーのデフォルトのチャンク移行方法に任せていたら、同じプロセスに 30 日かかっていたでしょう。
第二に、ワークロードへの影響は最小限に抑えられます。バランサーはデータを移行した後、と呼ばれるクリーンアップ操作を実行する必要があります。
第三に、ディスク容量が自動的に再利用されます。古いコレクションを削除すると、次のような操作を実行することなく、任意のコレクションで使用できるストレージ領域が解放されます。
たとえば、ある顧客は、最大のコレクションの再シャーディング操作が完了する前に、shard0 で 2.8 TB 近くを消費していました。
再シャーディングが完了すると、1.9TB のストレージ容量がすぐに返されました。ストレージの消費量は 2.7 TB から 873 GB になりました。
reshard-to-shard をいつ使用する必要がありますか?
回答:最初に任意のサイズのコレクションを任意の数のシャードにシャーディングする場合。
バランスが高速になるシナリオもいくつかありますが (100 GB 未満など)、それでも範囲の削除と、コンパクトまたは初期同期によるストレージの再利用を考慮する必要があります。したがって、容量がある場合は、シャーディングするコレクションがどれほど大きくても、リシャードからシャードへの再シャードをお勧めします。
reshard-to-shard を使用すべきでないのはどのような場合ですか?
次の場合には、リシャードからシャードへの戦術を使用しないでください。
- アプリケーションは、再シャーディングされたコレクションへのカットオーバーを可能にするために、2 秒間の書き込みのブロックを許容できません。
リシャーディングされるコレクションに対する書き込みをブロックできる期間は、デフォルトでは 2 秒です。ブロック期間を変更できる構成可能なパラメーターがあります。
- あなたのコレクションは時系列のコレクションです
- 時系列コレクションを再シャーディングしようとすると、時系列コレクションの再シャーディングがサポートされていないことを示すエラー メッセージが表示されます。
上記のシナリオでは、コレクションをシャーディングし、バランサーにデータを移行させるという従来の方法を使用します。
リシャード間の前提条件は何ですか?
- MongoDB 5.0 以降を実行しているMongoDBクラスター
- コレクションに適切なシャード キーを選択する必要があります。
- 一時的なシャード キーと目的のシャード キーの両方をサポートするために必要なインデックスを構築します。
- さらに、リシャーディングを使用してデータ移行速度を高速化するため、次の点についてよく理解しておく必要があります。
リシャーディングの要件と制限 。
再シャーディング操作を正常に実行するには、クラスターに以下が必要です。
- 各シャードで利用可能なシャードあたりのコレクション サイズの 1.2 倍。
- たとえば、1 TB のコレクションを 4 つのシャードに分散している場合、シャードされたコレクションのサイズは、4 つのシャードに分散すると 1 シャードあたり 250 GB になります。各シャードで少なくとも 300 GB のストレージを使用できるようにする必要があります。
- I/O 容量が 50% 未満
- CPU使用率が80%未満
Atlas を使用しているお客様のクラスターが、リシャーディングを実行するためのストレージ、I/O、CPU 要件を満たしていない場合は、一時的に簡単にリシャーディングを実行できます。
リシャードからシャードへの手法の概要
リシャード間の操作を実行するには、非常に簡単な 2 つの手順があります。
- 一時シャードキーにシャードする
- 希望のシャードキーにリシャードします
最初に一時シャード キーにシャーディングするのに、アプリケーションに悪影響を及ぼさないのはなぜですか?
説明しましょう!
ステップ 1: 一時的なシャード キーを使用してシャードする
現在、再シャーディングは同じシャード キーへの再シャーディングをサポートしていません (すでに望ましい状態にあるため、「操作なし」として成功します)。この制限を回避するには、リシャードからシャードへの手法では、目的のシャード キーとは異なる一時的なシャード キーに意図的にシャーディングする必要があります。 MongoDB は範囲シャーディングとハッシュ シャーディングの両方をサポートしているため、一時シャード キーは、コレクション用に選択した目的のシャード キーからわずかに変更することができます。
一時シャード キーでは、シャード キー フィールドの 1 つに対してのみ、異なるパーティション化戦略を選択する必要があります。 updateOne()、updateMany()、deleteOne() など、クエリにシャード キーを含める必要がある特定のクエリには制限があるため、別のパーティショニング戦略を使用することになります。 MongoDB は、クラスター内のシャード間でデータを分散する方法を決定する方法としてのみパーティション化戦略を使用し、ドキュメント内の値を変更することはありません。つまり、アプリケーションは両方のパーティション化戦略で、シャード キーを必要とするupdateOne
または別のクエリを利用できるということです。
たとえば、コレクション用に選択した目的のシャード キーが次の場合、
{"_id": "hashed"}
コレクションに最初に使用する一時シャード キーは次のとおりです。
{"_id": 1}
複合シャード キーの場合、シャード キー フィールドのうちの 1 つだけが異なるパーティション化戦略を使用する必要があります。たとえば、コレクション用に選択した目的のシャード キーが次の場合、
{ launch_vehicle: 1, payload: 1}
一時的なシャード キーは次のようになります。
{ launch_vehicle: 1, payload: "hashed"}
リシャードからシャードへの戦術では、一時シャード キーによるコレクションの最初のシャーディングが完了した後、長期的に使用するシャード キーへの即時再シャーディングが必要です。これにより、リシャーディング操作の実行中、99% 以上のデータが 1 つのシャードに保持され、ブロードキャスト クエリの影響が大幅に軽減されます。
データの 100% が 1 つのシャード上にあることを確認したい場合は、最初に一時シャード キーを使用してコレクションをシャーディングする前に、バランサーをオフにすることができます。バランサーを無効にすると、再シャーディングが開始される前に移行が発生しないことが保証されます。以下の例では、バランサーをオフにする方法について説明します。
一時的なシャード キーと目的のシャード キーの両方のインデックスが構築されているため、再シャーディング操作の実行中に、コレクションが一時的にパーティション化されている間に目的のシャード キーのインデックスを活用できるため、目的のシャード キーを利用するクエリのパフォーマンスが向上します。一時的なシャードキーによって。
ステップ 2: 希望のシャード キーに再シャードします
2 番目のステップは、リシャーディングがどのように機能するかという副作用を利用することを除いて、通常のリシャーディング操作を実行することです。
リシャーディングには 4 つの主要なフェーズがあります。
初期化- リシャーディング中のコレクションがサンプリングされ、新しいシャード キーに基づいてデータの新しい分布が決定されます。
インデックス- 再シャーディング操作では、新しいシャード キーに基づいてすべてのシャードに新しい空の一時的なシャード コレクションが作成され、既存のコレクションをサポートする非シャード キー インデックスを含むインデックスが構築されます。
クローン、キャッチアップ、および適用- 新しいシャード キーに従ってドキュメントがシャードにクローンされ、再シャーディング操作の実行中にドキュメントに加えられた変更が適用されます。
コミット- 一時コレクションの名前が変更され、再シャーディングされるコレクションの代わりとなり、古いコレクションは削除されます。
上記のフェーズを確認すると、高速なデータ移動、操作が完了するとシャード間で均等に分散されるシャード コレクション、および一度に解放されたストレージ スペースの利点がどのように得られるかがわかります。
再シャーディング操作が完了したら、一時的なシャード キー インデックスの削除や、定常状態のニーズに合わせてクラスターやストレージのスケールダウンなどのクリーンアップ操作を実行できます。
リシャードからシャードへの例
たとえば、フライトが遅延する可能性がある場合に顧客に通知できるように、民間航空機を追跡するアプリケーションを開発しているとします。アプリケーションのクエリ パターンを調査し、適切なシャード キーにどのような属性が寄与するかを確認しました。
コレクション用に選択したシャード キーは次のとおりです。
{ airline: 1, flight_number: 1, date: "hashed" }
シャード キーが決定したら、再シャード間の操作を実行するための前提条件のチェックを開始できます。まず、一時的なシャード キーを生成します。前述したように、一時シャード キーは、目的のシャード キーをわずかに変更したバージョンにする必要があります。
したがって、選択した一時的なシャード キーは次のようになります。
{ airline: 1, flight_number: 1, date: 1}
次に、一時シャード キーと最終シャード キーの両方をサポートするインデックスを構築します。
インデックスは、Mongo シェルを使用してdb.collection.createIndexes()
コマンドで作成できます。
db.flight_tracker.createIndexes([ {"airline": 1, "flight_number": 1, date: "hashed"}, {"airline": 1, "flight_number": 1, date: 1} ])
インデックスの構築は、次のコマンドで mongo シェルを使用して監視できます。
db.adminCommand({ currentOp: true, $or: [ { op: "command", "command.createIndexes": { $exists: true } }, { op: "none", "msg" : /^Index Build/ } ] })
コレクションをシャーディングしてから再シャーディングが呼び出されるまでの間に移行が発生しないようにしたい場合は、次のコマンドを実行してバランサーをオフにすることができます。
sh.stopBalancer()
MongoDB クラスターが Atlas にデプロイされている場合は、Atlas UI を使用して利用可能なメトリクスを簡単に確認できます。これにより、クラスターに十分な空きストレージと、再シャーディング操作を実行するための CPU および I/O ヘッドルームがあることがわかります。
利用可能なストレージ容量または I/O ヘッドルームが十分でない場合は、ストレージを拡張できます。 CPU ヘッドルームが不足している場合は、クラスターをスケールできます。ストレージとクラスターの両方のスケーリングは、Atlas UI を介して簡単に実行できます。
クラスター構成へのアクセスは簡単で、グループにデプロイされたすべてのクラスターが表示されるグループの概要画面から行うことができます。
すべての前提条件が満たされていると、再シャードからシャードへのプロセスの最初の部分、つまり一時シャード キーを使用したコレクションのシャーディングを開始できます。
その後、Mongo シェルと sh.shardCollection() コマンドを使用してコレクションをシャード化できます。
sh.shardCollection("main.flight_tracker", { airline: 1, flight_number: 1, date: 1} )
sh.shardCollection() は完了するとドキュメントを返します。操作が成功した場合、フィールド ok の値は 1 になります。
{ collectionsharded: 'main.flight_tracker', ok: 1, '$clusterTime': { clusterTime: Timestamp({ t: 1684160896, i: 25 }), signature: { hash: Binary(Buffer.from("7cb424a56cacd56e47bf155bc036e4a4da4ad6b6", "hex"), 0), keyId: Long("7233411438331559942") } }, operationTime: Timestamp({ t: 1684160896, i: 21 }) }
コレクションがシャーディングされたら、すぐにコレクションの再シャーディングに進むことができます。
コレクションを目的のシャード キーにリシャードするには、mongo シェルで sh.reshardCollection() を使用します。
sh.reshardCollection("main.flight_tracker", { airline: 1, flight_number: 1, date: "hashed" })
mongo シェルで sh.status() コマンドを実行すると、新しいコレクションの名前の形式が<db_name>.system.resharding.<UUID>
である出力に新しいコレクションが表示されます。これは、リシャーディングが目的のシャード キーに従ってデータを構築および配布するコレクションです。
Flight_tracker コレクションのリシャーディング操作のステータスを監視するには、次のコマンドを使用できます。
db.getSiblingDB("admin").aggregate([ { $currentOp: { allUsers: true, localOps: false } }, { $match: { type: "op", "originatingCommand.reshardCollection": "main.flight_tracker" } } ])
コマンドの出力により、リシャーディング操作が現在実行されているステージと、remainingOperationTimeestimateSecs フィールドを介して完了までの推定時間が通知されます。再共有が完了するまでの推定時間は悲観的であり、再共有操作にかかる時間は報告されているよりも大幅に短いことに注意してください。
各シャードのデータ サイズが、再シャーディングされるコレクションのサイズをクラスター内のシャードの数で割った値だけ増加すると、再シャーディング操作は完了に近づくはずです。たとえば、1 TB のコレクションが 4 つのシャードにまたがって再シャーディングされる場合、各シャードが 250 GB を書き込んだ時点で再シャーディング操作が完了する必要があります (シャード上で挿入、更新、または削除される他のデータは考慮されていません)。
クラスターが Atlas にデプロイされている場合は、クラスターの [メトリック] タブを使用して、Atlas UI 経由でリシャーディング操作の進行状況を監視することもできます。
MongoDB 6.0 以降を実行している Atlas クラスターの場合 - シャード データ サイズ表示オプションを使用し、
<db_name>.system.resharding.<UUID>
の構文でコレクションを選択できます。このビューは一時コレクションを分離し、新しいコレクションのデータ サイズの増加のみを表示します。
MongoDB 5.0 を実行している Atlas クラスターの場合、db 論理データ サイズ表示オプションを使用できます。このビューでは、コレクション レベルの分離は許可されません。
リシャーディングの実行中、主に監視する必要があるクラスターからの 3 つのメトリックは次のとおりです。
- 利用可能なストレージ - 利用可能なストレージをすべて消費すると、クラスターが不安定になる可能性があります
- CPU 使用率 - CPU 使用率が高いと、クラスターのパフォーマンスが低下する可能性があります
- I/O 使用量 - 容量を超える I/O 使用量は、クラスターのパフォーマンスの低下につながる可能性があります
リシャーディングがクラスターに悪影響を与えることが心配な場合は、次のコマンドを使用して、プロセスのコミット部分に到達する前にリシャーディング操作を即座に中止できます。
sh.abortReshardCollection("main.flight_tracker")
コレクションのシャーディングと再シャーディングの間に移行が発生しないようにバランサーをオフにした場合は、次のコマンドを使用してバランサーを再びオンにします。
sh.startBalancer()
リシャーディング操作が完了すると、操作が成功したかどうかが呼び出し元のクライアントに返されます。
リシャーディングは長時間実行される操作であり、Mongo シェル セッションを閉じている可能性があるため、詳細が必要な場合は、リシャーディング監視集計を使用してシャーディング操作がまだ実行中かどうかを確認できます。
db.collection.getShardDistribution
を使用して、操作が成功したかどうかを確認できます。
db.flight_tracker.getShardDistribution()
リシャーディングが正常に完了すると、シャード間で分散が均等になった出力が表示されるはずです。
MongoDB 6.0 以降の場合、均一性はシャードごとのデータ サイズによって決定されるため、db.collection.getShardDistribution の出力では各シャードにほぼ同じ量のデータが表示されるはずです。
MongoDB 5.0 の場合、均一性はシャードあたりのチャンク数によって決まるため、db.collection.getShardDistribution の出力では各シャードのチャンク数が等しいことがわかります。
クラスターが Atlas にデプロイされている場合は、「メトリック」タブから Atlas UI を使用して、リシャーディング操作が成功したかどうかを判断できます。
MongoDB 6.0 以降を実行している Atlas クラスターの場合、シャード データ サイズ表示オプションを使用して、再シャーディングが行われたコレクションを選択できます。シャードごとに同じ量のデータが表示されるはずです。
MongoDB 5.0 を実行している Atlas クラスターの場合、チャンク表示オプションを使用して、リシャーディングが行われたコレクションを選択できます。クラスター内のすべてのシャードにほぼ同じ数のチャンクが表示されるはずです。
シャード データ サイズとチャンク数の両方について、Atlas UI では、名前を変更して古いものを削除する前に、一時的に<db_name>.system.resharding.<UUID>
のコレクション名形式を使用して再シャーディングするため、関連するメトリックの急激な増加が表示されます。古いシャードキーを使用してコレクションを作成します。
再シャーディングが中止された場合、 db.collection.getShardDistribution
の出力には、コレクションが最初にシャードされたシャード上のデータの大部分が表示される可能性があります。リシャーディングによる中止はまれですが、リシャーディングが 2 秒以内にコレクションのカットオーバーを実行できなかったためと考えられます。
その場合は、クラスターのトラフィックが少ない時間帯にコミットが試行されるように、リシャーディングの開始のタイミングを調整することをお勧めします。あるいは、アプリケーションが 2 秒を超える書き込みのブロックを許容できる場合は、 reshardingCriticalSectionTimeoutMillis パラメーターで期間をデフォルトの 2000 ミリ秒を超えて増やすことで、コミット時間を変更できます。
再シャーディング操作が完了したら、一時的なシャード キー インデックスの削除や、定常状態のニーズに合わせてクラスターやストレージのスケールダウンなどのクリーンアップ操作を実行できます。
mongo シェルでdb.collection.dropIndex()
コマンドを使用して一時インデックスを削除できるようになりました。
db.flight_tracker.dropIndex( {"airline": 1, "flight_number": 1, "date": 1} )
よくある質問
リシャードからシャードへの所要時間はどれくらいですか?
コレクションのサイズ、コレクションのインデックスの数とサイズ、クラスター内のシャードの数によって異なりますが、48 の 4 つのシャードにまたがる 10 のインデックスを持つ 4TB のコレクションをシャードにリシャードできると確信しています。時間以内。バランサーに移行を処理させると 30 日以上かかります。
バランサーにデータを移行させるよりもリシャーディングの方が速いのはなぜですか?
バランサーとリシャーディングがデータを移行する方法の内部は異なります。リシャーディングはチャンク移行とは異なる順序でドキュメントを読み取ります。リシャーディングは古いコレクションの削除で終了するため、範囲の削除によってディスク領域が解放されるのを待つ必要はありません。
一意性の制約があり、ハッシュ インデックスが一意性の強制をサポートしていないコレクションに対してリシャードからシャードへの実行を使用したいと考えています。
コレクションに一意性の制約がある場合は、リシャードからシャードを使用できますが、別のアプローチを取る必要があります。パーティショニング戦略を変更する代わりに、一時的なシャード キーにフィールドを追加することで、目的のシャード キーに再シャードする機能がロック解除されます。たとえば、希望するシャード キーが次の場合:
{ launch_vehicle: 1, payload: 1}
一時的なシャード キーは次のようになります。
{ launch_vehicle: 1, payload: 1, launch_pad: 1}
クエリにシャード キーを含める必要があるクエリ (例: updateOne()、updateMany()、deleteOne()) の制限に注意してください。再シャーディング操作が完了するまでクエリを正常に実行するためにシャード キーが必要なすべてのシナリオで、アプリケーションに一時シャード キーを含める必要があります。
進行中のリシャーディング操作を監視するにはどうすればよいですか?
次のコマンドを実行します。
db.getSiblingDB("admin").aggregate([ { $currentOp: { allUsers: true, localOps: false } }, { $match: { type: "op", "originatingCommand.reshardCollection": "<database>.<collection>" } } ])
進行中のリシャーディング操作を停止するにはどうすればよいですか?
次のコマンドを実行すると、再シャーディング操作が即座に中止されます。
sh.abortReshardCollection("<database>.<collection>")
リシャーディングがクラスターのパフォーマンスに影響を与えるのではないかと心配しています。
前述の再シャーディング要件を満たしている場合、この操作はクラスターのパフォーマンスに影響を与えません。ただし、クラスターが Atlas にデプロイされている場合は、再シャード間の操作の実行中にクラスターを一時的にスケールアップし、操作の完了後にクラスターをスケールダウンして戻すことができます。
リシャーディング操作の実行中にクラスターのどのようなメトリクスを監視する必要がありますか?
利用可能なストレージ容量 - いずれかのシャードの利用可能なストレージが 100 GB 未満の場合は、再シャーディングを中止する必要があります。
CPU 使用率 - クラスターが利用可能なコンピューティング リソースをすべて消費している場合は、リソース競合が発生する可能性があるため、リシャーディングを中止する必要があります。
I/O 消費 - クラスターが利用可能な IOPS をすべて消費している場合、リソース競合が発生する可能性があるため、リシャーディングを中止する必要があります。
一時的なコレクションはすべてのシャードに均等に分散されているように見えますが、リシャーディングが完了しないのはなぜですか?
再シャーディングが目的のシャード キーを使用してコレクションにカットオーバーできるようにするには、その前に、
追いつく リシャーディングの開始以降に発生したすべての書き込みが含まれます。書き込みワークロードが重い場合、キャッチアップ フェーズが完了するまでに長時間かかる可能性があります。
私のアプリケーションは 1 秒を超える書き込みブロックに耐えることができません。再シャーディングされるコレクションへの書き込みがブロックされる期間を変更できますか?
はい、ただし、リシャーディング操作はデフォルトで、カットオーバーが 1 秒未満で完了できると推定される場合に新しいコレクションへのカットオーバーを試行するため、このオプションが頻繁に使用されることは予想されていません。アプリケーションが、リシャーディング中のコレクションへの書き込みが 2 秒間ブロックされることに耐えられない場合は、 reshardingCriticalSectionTimeoutMillis パラメーターを変更して、書き込みを 1 秒だけブロックすることができます。
- この値を減らすと、クリティカル セクションがカットオーバーを完了するまでリシャーディング操作が待機できるタイムアウトが減少するため、リシャーディング操作が中止される可能性が高まることに注意してください。
次のコマンドを実行します。
db.adminCommand({ setParameter: 1, reshardingCriticalSectionTimeoutMillis: 1000 })
Pexels で見つけたpanumas nikhomkhaiによる見出しの写真。