A partir de MongoDB 8.2, las lecturas secundarias en clústeres particionados podrían finalizar automáticamente si existe riesgo de pérdida de documentos debido a migraciones por fragmentos.
Para respaldar este nuevo comportamiento, MongoDB 8.2 introduce los siguientes cambios:
Agregar
terminateSecondaryReadsOnOrphanCleanupParámetrotrue(predeterminado:)Nota
Si
terminateSecondaryReadsOnOrphanCleanupse establece enfalse, el servidor no termina las lecturas y podría perder documentos en colecciones fragmentadas debido a migraciones de fragmentos. Este es el comportamiento por defecto en MongoDB 8.1 o anterior. Para aprender más, consulta Deshabilitar la terminación de lectura secundaria.Aumenta
orphanCleanupDelaySecsel valor por defecto de900segundos a3600segundos (1 hora)
Comportamiento
De forma predeterminada, un clúster fragmentado realiza las siguientes operaciones cuando se confirma una migración de fragmentos:
La partición de origen inicia un proceso de limpieza de huérfanos para borrar documentos que migraron a una partición diferente.
El fragmento espera a que se completen todas las lecturas preexistentes en el fragmento principal.
El fragmento espera
orphanCleanupDelaySecssegundos adicionales (valor predeterminado: 1 hora).La partición borra documentos huérfanos.
Los secundarios terminan las lecturas que comenzaron antes de que se completara la migración.
Los secundarios replican eliminaciones de documentos huérfanos.
Finalizar las lecturas secundarias antes de eliminar documentos huérfanos garantiza que las lecturas secundarias de larga duración no omitan ningún documento eliminado durante el proceso de limpieza.
Monitoring
Puede supervisar las lecturas secundarias terminadas debido a la limpieza de huérfanos de las siguientes maneras:
Compruebe el estado del servidor de su nodo secundario con el siguiente
mongoshcomando:db.serverStatus().metrics.operation.killedDueToRangeDeletionRevise sus registros
mongod. Cada terminación genera una entrada de registro como la del siguiente ejemplo:
{ "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 } }
Gestión de lecturas secundarias de larga duración
Si su aplicación realiza lecturas secundarias que superan las 1 horas en clústeres fragmentados que realizan migraciones de fragmentos, es posible que encuentre QueryPlanKilled errores (código 175 de error) debido a lecturas finalizadas.
El método recomendado para gestionar las lecturas secundarias de larga duración es implementar un mecanismo de reanudación en su aplicación.
También puedes gestionar lecturas secundarias de larga duración con las siguientes estrategias alternativas:
Implementar mecanismo de reanudación
Un mecanismo de reanudación permite a tu aplicación crear una nueva operación de lectura que comience donde terminó la operación de lectura anterior.
Para implementar un mecanismo de reanudación efectivo, tu aplicación debe usar un ordenamiento coherente para los resultados de sus queries. Ten en cuenta los siguientes factores al seleccionar un orden de clasificación para tu mecanismo de reanudación:
La operación de clasificación debe utilizar un campo indexado para una ejecución eficiente de la consulta.
El campo de ordenación debe contener valores únicos.
Si los valores del campo de ordenación no son únicos, tu aplicación debe implementar lógica adicional para gestionar documentos que compartan el mismo valor de ordenación.
Ejemplo
Considere una base de datos cities que contiene una colección zipcodes con la siguiente estructura:
{ "state": "NY", "city": "NEW YORK", "zipcode": "00501" }
Para este ejemplo, supongamos que los valores del campo zipcode son únicos.
El siguiente código JavaScript realiza una operación de lectura secundaria para recuperar todos los documentos donde el state es NY e implementa un mecanismo de reanudación para gestionar errores 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 } } }
Al revisar la base de datos de ejemplo y la lógica de la aplicación, considere lo siguiente:
El código de ejemplo gestiona
QueryPlanKillederrores con un mecanismo de reanudación que ordena porzipcode. Ordenar por el campozipcodegarantiza un orden coherente y un valor de orden único para cada documento. Esto permite que la aplicación reanude la operación de lectura exactamente donde se detuvo.La
cities.zipcodescolección implementa un{state: 1, zipcode: 1}índice compuesto para garantizar la eficiencia de las queries del mecanismo de reanudación. La implementación de este índice compuesto evita tanto escaneos de colección como ordenamientos en memoria, y admite operaciones de filtrado y ordenamiento. Para obtener más información sobre cómo crear índices efectivos, consulta La guía ESR (Igualdad, Ordenación, Rango).El error
QueryPlanKilled(código de error175) puede ocurrir por razones distintas a la interrupción de lecturas secundarias. Para gestionar de manera precisa los erroresQueryPlanKilled, debe analizar el campoerrmsg. MongoDB devuelve el siguiente mensaje de error cuando finaliza una lectura secundaria:
{ code: 175, name: QueryPlanKilled, categories: [CursorInvalidatedError], errmsg: "Read has been terminated due to orphan range cleanup" }
Cuando la aplicación encuentra un error de
QueryPlanKilleddebido a la limpieza de rangos huérfanos, utiliza el código postal procesado exitosamente como punto de partida para la query reanudada. El operador$gtgarantiza que la aplicación no procese documentos duplicados.
Prueba tus mecanismos de reanudación en un entorno de prueba y supervisa tu clúster de producción para comprender con qué frecuencia se terminan las lecturas secundarias. Si las terminaciones ocurren con frecuencia, puede que debas ajustar tus patrones de query o considerar enfoques alternativos de acceso a los datos. Para aprender cómo supervisar tu clúster para estos errores, consulta Supervisión.
Aumentar orphanCleanupDelaySecs
El parámetro de servidor orphanCleanupDelaySecs controla el tiempo que MongoDB espera antes de borrar un fragmento migrado de la partición de origen.
Aumentar orphanCleanupDelaySecs permite que las operaciones de lectura secundarias se ejecuten durante un periodo de tiempo más largo. Puedes configurar el orphanCleanupDelaySecs tanto al inicio como en tiempo de ejecución.
El siguiente comando establece orphanCleanupDelaySecs en 2 horas:
db.adminCommand({ setParameter: 1, orphanCleanupDelaySecs: 7200 })
Importante
Incrementar orphanCleanupDelaySecs significa que los documentos huérfanos permanecen en los nodos durante un periodo de tiempo más largo. Si aumentas este valor, ejecutar una query que utiliza un índice pero no incluye la clave de partición puede resultar en un rendimiento degradado, ya que la query debe filtrar más documentos huérfanos antes de devolver los resultados.
Desactivar la terminación de lectura secundaria
Nota
En MongoDB 8.1 o versiones anteriores, los clústeres fragmentados no finalizan automáticamente las lecturas secundarias de larga duración. Para que esto se ajuste a MongoDB 8.2 o versiones posteriores, deshabilite la finalización de lecturas secundarias.
El parámetro terminateSecondaryReadsOnOrphanCleanup del servidor controla si las lecturas secundarias de larga duración terminan automáticamente antes de la eliminación de documentos huérfanos.
Puede desactivar la terminación de lectura secundaria configurando terminateSecondaryReadsOnOrphanCleanup en false. Puede configurar este parámetro al iniciar o ejecutar.
El siguiente comando establece terminateSecondaryReadsOnOrphanCleanup en false:
db.adminCommand({ setParameter: 1, terminateSecondaryReadsOnOrphanCleanup: false })
Advertencia
Si esta funcionalidad está desactivada y las migraciones de fragmentos afectan a la colección objetivo, es posible que las lecturas secundarias no devuelvan todos los documentos.
Desactivar el balanceador
Puedes evitar la finalización automática de lecturas secundarias de larga duración desactivando el balanceador y no realizando ninguna migración manual.
Para desactivar el balanceador en colecciones específicas, utiliza el campo enableBalancing del comando configureCollectionBalancing.
Para restringir las operaciones del balanceador a períodos específicos, consulte Programar la ventana de balanceo.
Advertencia
Desactivar el balanceador durante períodos prolongados puede provocar particiones desequilibradas, lo que reduce el rendimiento del clúster. Sólo desactive el balanceador si es necesario para tu caso de uso.