Docs Menu
Docs Home
/
データベース マニュアル
/

シャーディングされたクラスターで長時間実行されているセカンダリ読み取り

MongoDB 8.2 以降では、チャンクの移行によりドキュメントが欠落するリスクがある場合、シャーディングされたクラスター内のセカンダリ読み取りが自動的に終了することがあります。

この新しい動作をサポートするために、 MongoDB 8.2 では次の変更が導入されています。

  • terminateSecondaryReadsOnOrphanCleanup パラメータを追加しました(デフォルト: true

    注意

    terminateSecondaryReadsOnOrphanCleanupfalse に設定されている場合、サーバーは読み取りを終了せず、チャンクの移行によってシャーディングされたコレクション内のドキュメントが失われる可能性があります。これはMongoDB 8.1 またはそれ以前のバージョンのデフォルトの動作です。詳しくは、セカンダリ読み取りの終了を無効にする を参照してください。

  • orphanCleanupDelaySecs のデフォルト値を 900 秒から 3600 秒(1 時間)に増加させます

デフォルトでは 、シャーディングされたクラスターは、チャンク移行がコミットされるときに次の操作を実行します。

  1. ソース シャードは、別のシャードに移行されたドキュメントを削除するために 孤立したクリーンアップ プロセスを開始します。

    1. シャードは、プライマリに存在する既存の読み取りが完了するのを待機します。

    2. シャードは追加の orphanCleanupDelaySecs 秒(デフォルト: 1 時間)待機します。

    3. シャードは 孤立したドキュメント を削除します。

  2. セカンダリ は、移行が完了する前に開始された読み取りを終了します。

  3. セカンダリ は孤立したドキュメントの削除 を複製します。

チャンクの移行により終了される、実行中のセカンダリ読み取りのライフサイクルを示す図。

孤立したドキュメントを削除する前にセカンダリ読み取りを終了することで、長時間実行されているセカンダリ読み取りでも、クリーンアップ プロセスによって削除されたドキュメントを見逃しません。

孤立したクリーンアップによって終了したセカンダリ読み取りは、次の方法で監視できます。

  • 次の mongosh コマンドを使用して、セカンダリノードのサーバーステータスを確認します。

    db.serverStatus().metrics.operation.killedDueToRangeDeletion

  • mongod ログを確認します。終了のたびに、次の例のようなログエントリが作成されます。

{
"t": {
"$date": "2025-06-11T12:11:43.361+02:00"
},
"s": "I",
"c": "SHARDING",
"id": 10016300,
"svc": "S",
"ctx": "conn93",
"msg": "Read has been terminated due to orphan range cleanup",
"attr": {
"type": "command",
...
"workingMillis": 0,
"durationMillis": 0,
"orphanCleanupDelaySecs": 3600
}
}

アプリケーションが、チャンク移行を実行するシャーディングされたクラスターで 1 時間を超えるセカンダリ読み取りを実行すると、読み取りの終了によって QueryPlanKilled エラー(エラー コード 175)が発生する可能性があります。

長時間実行されているセカンダリ読み取りを管理するための推奨方法は、アプリケーションに再開メカニズムを実装することです。

また、次の代替戦略を使用して、実行時間が長いセカンダリ読み取りを管理することもできます。

再開メカニズムを使用すると、アプリケーションは新しい読み取り操作を作成し、前の読み取り操作が終了した場所から開始できます。

効果的な再開メカニズムを実装するには、アプリケーションでクエリ結果に対して一貫したソート順序を使用する必要があります。再開メカニズムでソート順序を選択する際には、次の要素を考慮してください。

  • クエリを効率的に実行するために、ソート操作ではインデックス付きフィールドを利用する必要があります。

  • ソートフィールドには一意の値を含める必要があります。

    • ソートフィールドの値が一意でない場合、アプリケーションは、同じソート値を共有するドキュメントを処理するための追加のロジックを実装する必要があります。

次の構造を持つ zipcodesコレクションを含む citiesデータベースを考えてみましょう。

{
"state": "NY",
"city": "NEW YORK",
"zipcode": "00501"
}

この例では 、zipcodeフィールド値は一意であると仮定しています。

次のJavaScriptコードでは、セカンダリ読み取り操作を実行して、stateNY であるすべてのドキュメントを取得し、QueryPlanKilled エラーを処理するための再開メカニズムを実装します。

let readDoc;
let latestZip;
let cursor = db.getSiblingDB("cities").zipcodes.find({
state: "NY"
})
.sort({zipcode: 1})
.readPref("secondary");
while(cursor.hasNext()) {
try {
readDoc = cursor.next();
// process `readDoc` here
latestZip = readDoc.zipcode;
} catch (err) {
if (err.code === 175 &&
err.errmsg.includes("Read has been terminated due to orphan range cleanup")) {
console.log("Query terminated, resuming from zipcode:", latestZip);
cursor = db.getSiblingDB("cities").zipcodes.find({
state: "NY",
zipcode: {$gt: latestZip}
})
.sort({zipcode: 1})
.readPref("secondary");
} else {
throw err; // Rethrow non-termination errors
}
}
}

例データベースとアプリケーションロジックを確認する際には、次の点を考慮してください。

  • この例コードでは、zipcode でソートする再開メカニズムを使用して QueryPlanKilled エラーを処理します。zipcodeフィールドでソートすると、各ドキュメントに対して一貫した順序と一意のソート値が確保されます。これにより、アプリケーションは読み取り操作が終了した場所で正確に再開できるようになります。

  • cities.zipcodesコレクションには、再開メカニズム クエリの効率を確保するために {state: 1, zipcode: 1}複合インデックスが実装されています。この複合インデックスを実装すると、コレクションスキャンとメモリ内ソートの両方が防止され、フィルター操作とソート操作がサポートされます。効果的なインデックスの作成の詳細については、ESR(Equality、Sort、Range)ガイドラインを参照してください。

  • QueryPlanKilled エラー(エラー コード 175)は、セカンダリ読み取りが終了した以外の理由で発生する可能性があります。QueryPlanKilled エラーを正確に処理するには、errmsgフィールドを解析する必要があります。MongoDB は、セカンダリ読み取りを終了するときに次のエラー メッセージを返します。

{
code: 175,
name: QueryPlanKilled,
categories: [CursorInvalidatedError],
errmsg: "Read has been terminated due to orphan range cleanup"
}
  • アプリケーションで孤立した範囲のクリーンアップが原因で QueryPlanKilled エラーが発生した場合、再開されたクエリの開始点として最後に正常に処理された郵便番号を使用します。$gt 演算子により、アプリケーションは重複するドキュメントを処理しないようになります。

テスト環境で再開メカニズムをテストし、本番クラスターをモニターして、セカンダリ読み取りが終了する頻度を把握します。終了が頻繁に発生する場合は、クエリ パターンを調整するか、別のデータアクセスアプローチを検討する必要があるかもしれません。こうしたエラーが発生しないかクラスターを監視する方法については、監視を参照してください。

orphanCleanupDelaySecsサーバーパラメータは、移行された チャンク をソース シャードから削除するまでにMongoDB が待機する時間を制御します。

orphanCleanupDelaySecs を増やすと、セカンダリ読み取り操作がより長時間実行できるようになります。orphanCleanupDelaySecs は、スタートアップと実行時に設定できます。

次のコマンドは、orphanCleanupDelaySecs を 2 時間に設定します。

db.adminCommand({
setParameter: 1,
orphanCleanupDelaySecs: 7200
})

重要

orphanCleanupDelaySecs を増加させると、孤立したドキュメントがノード上に一定期間残ります。この値を増やすと、インデックスを使用するがシャードキーを含まないクエリを実行すると、クエリが結果を返す前に孤立したドキュメントをフィルタリングする必要があるため、パフォーマンスが低下する可能性があります。

注意

MongoDB 8.1 またはそれ以前のバージョンでは、シャーディングされたクラスターは長時間実行されているセカンダリ読み取りを自動的に終了しません。MongoDB 8.2 以降でこの動作を実現するには、セカンダリ読み取りの終了を無効にします。

terminateSecondaryReadsOnOrphanCleanupサーバーパラメータは、孤立したドキュメントが削除される前に、長時間実行されているセカンダリ読み取りを自動的に終了するかどうかを制御します。

terminateSecondaryReadsOnOrphanCleanupfalse に設定することで、セカンダリ読み取りの終了を無効にすることができます。このパラメーターは、スタートアップ時に設定できます。

次のコマンドは、terminateSecondaryReadsOnOrphanCleanupfalse に設定します。

db.adminCommand({
setParameter: 1,
terminateSecondaryReadsOnOrphanCleanup: false
})

警告

この機能が無効になっており、チャンクの移行が ターゲットコレクションに影響する場合、セカンダリ読み取りがすべてのドキュメントを返さない可能性があります。

バランサーを無効にして手動移行を実行しないことで、実行時間の長いセカンダリ読み取りが自動的に終了しないようにできます。

特定のコレクションのバランサーを無効にするには、configureCollectionBalancing コマンドの enableBalancingフィールドを使用します。

バランサー操作を特定の時間に制限するには、バランシング ウィンドウのスケジュールを参照してください。

警告

バランサーを長期間無効にすると、シャードのバランスが取れず、クラスターのパフォーマンスが低下する可能性があります。ユースケースで必要な場合のみ、バランサーを無効にします。

戻る

AutoMerger

項目一覧