Este tema describe cómo supervisar el progreso de las tareas que agregan o eliminan nodos shard y cómo identificar condiciones anómalas que podrían bloquear dichas tareas.
Contexto
Después de agregar o eliminar nodos shard de una instancia de clúster fragmentado, es posible que la tarea permanezca incompleta durante un periodo prolongado. Las siguientes secciones explican cómo solucionar este problema.
Antes de empezar, comprenda los siguientes conceptos:
Comprenda los modos de despliegue de las instancias de conjunto de réplicas y de clúster fragmentado de MongoDB, así como las diferencias entre estas arquitecturas. Para obtener más información, consulte Replica set architecture y Sharded cluster architecture.
Comprenda cómo funciona el Balancer de MongoDB. Para obtener más información, consulte Manage the MongoDB Balancer.
Comprenda cómo divide los datos MongoDB. MongoDB particiona los datos en chunks.
Conozca los comandos comunes de operación y mantenimiento para instancias de clúster fragmentado de MongoDB, como
sh.status().Sepa utilizar mongo shell, mongosh u otras herramientas de visualización.
Consultar el progreso de la tarea
Paso 1: Comprobar si el Balancer está habilitado
La migración de chunks durante la adición o eliminación de shards depende del Balancer. Si el Balancer está deshabilitado, ocurren los siguientes problemas:
Al agregar un nodo shard: Los datos de los chunks no pueden migrar al nuevo nodo shard y el nodo no puede gestionar el tráfico del servicio.
Al eliminar un nodo shard: Los chunks del shard objetivo no pueden migrarse, lo que bloquea la tarea de eliminación.
Habilite el Balancer para garantizar una migración normal de chunks. Para obtener instrucciones, consulte Manage the MongoDB Balancer.
Utilice uno de los siguientes métodos para comprobar si el Balancer está habilitado:
-
Método 1: Ejecute el comando
sh.status().Si el Balancer está habilitado, la salida será similar al siguiente ejemplo.
... autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: yes Balancer active window is set between 08:30 and 11:30 server local time ...Si la salida muestra
“Currently enabled: no”, el Balancer está deshabilitado. -
Método 2: Ejecute el comando
sh.getBalancerState().Si el comando devuelve
true, el Balancer está habilitado.Si el comando devuelve
false, el Balancer está deshabilitado.
Paso 2: Comprobar si la ventana del Balancer es demasiado corta
El Balancer controla la velocidad de migración de chunks y solo migra chunks durante su ventana activa. Si la migración no finaliza dentro de la ventana actual, se reanuda en la siguiente hasta completarse. Una ventana corta puede ralentizar las tareas de adición o eliminación de shards. Para ajustar la ventana del Balancer, consulte Manage the MongoDB Balancer.
Utilice uno de los siguientes métodos para comprobar la ventana del Balancer:
-
Método 1: Ejecute el comando
sh.status().El siguiente ejemplo muestra una ventana del Balancer de 08:30 a 11:30 hora local del servidor (3 horas en total).
... autosplit: Currently enabled: yes balancer: Currently enabled: yes Currently running: yes Balancer active window is set between 08:30 and 11:30 server local time ... -
Método 2: Ejecute el comando
sh.getBalancerWindow().El siguiente ejemplo muestra claramente la hora de la ventana, lo cual resulta especialmente útil cuando existen muchas colecciones fragmentadas.
{ "start" : "08:30", "stop" : "11:30" }
Paso 3: Recopilar la información necesaria para estimar el progreso de la tarea
Para versiones de MongoDB anteriores a la 6.0
Esta sección aplica a las siguientes versiones:
Instancias de MongoDB anteriores a la versión 6.0.
Instancias de MongoDB 6.0 con una versión menor del motor anterior a la 7.0.1 (versión base 6.0.3). Para consultar la versión menor de su motor, consulte MongoDB minor version guide.
Antes de estimar el progreso de la tarea, obtenga estadísticas de ejecución del Balancer (recuentos de éxitos y fallos) e información de chunks para las colecciones fragmentadas pendientes de migración.
Puede obtener los resultados de ejecución del Balancer y la información sobre los chunks de las tablas fragmentadas pendientes de migración mediante los dos métodos siguientes:
-
Método 1: Utilice la salida del comando
sh.status().Céntrese en dos partes de la salida de
sh.status(). La primera parte muestra los resultados recientes del Balancer, como en este ejemplo.... balancer: Collections with active migrations: <db>.<collection> started at Wed Sep 27 2023 10:25:21 GMT+0800 (CST) Failed balancer rounds in last 5 attempts: 0 Migration Results for the last 24 hours: 300 : Success databases: ...La segunda parte muestra detalles de los chunks para las colecciones fragmentadas, como en este ejemplo.
... databases: ... { "_id" : "<db>", "primary" : "d-xxxxxxxxxxxxxxx3", "partitioned" : true, "version" : { "uuid" : UUID("3409a337-c370-4425-ad72-8b8c6b0abd52"), "lastMod" : 1 } } <db>.<collection> shard key: { "<shard_key>" : "hashed" } unique: false balancing: true chunks: d-xxxxxxxxxxxxxxx1 13630 d-xxxxxxxxxxxxxxx2 13629 d-xxxxxxxxxxxxxxx3 13652 d-xxxxxxxxxxxxxxx4 13630 d-xxxxxxxxxxxxxxx5 3719 too many chunks to print, use verbose if you want to force print ...En este ejemplo, “d-xxxxxxxxxxxxxxx5” es el nodo shard recién agregado. También puede ejecutar el comando
getShardDistributionen la base de datos que contiene la colección fragmentada para obtener detalles de la distribución de chunks, como se muestra a continuación.use <db> db.<collection>.getShardDistribution() -
Método 2: Lea los datos relevantes directamente desde la base de datos config.
Consulte las estadísticas de chunks agregadas por shard de la siguiente manera.
db.getSiblingDB("config").chunks.aggregate([{$group: {_id: "$shard", count: {$sum: 1}}}])Para ver los chunks en un shard específico agrupados por namespace, ejecute el siguiente comando.
db.getSiblingDB("config").chunks.aggregate([{$match: {shard: "d-xxxxxxxxxxxxxx"}},{$group: {_id: "$ns", count: {$sum: 1}}}])Para contar los chunks migrados correctamente a un nodo shard específico en las últimas 24 horas, ejecute el siguiente comando.
// details.to specifies the destination shard for chunk migration // Use ISODate to define the time range in the time field db.getSiblingDB("config").changelog.find({"what" : "moveChunk.commit", "details.to" : "d-xxxxxxxxxxxxx","time" : {"$gte": ISODate("2023-09-26T00:00:00")}}).count()
Para versiones de MongoDB 6.0 y posteriores
Esta sección aplica a las siguientes versiones:
Instancias de MongoDB versión 6.0 y posteriores.
Instancias de MongoDB 6.0 con una versión menor del motor 7.0.1 (versión base 6.0.3) o posterior. Para consultar la versión menor de su motor, consulte MongoDB minor version guide.
Antes de estimar el progreso de la tarea, céntrese en la distribución de datos entre los shards. Aún puede usar la salida de sh.status() como referencia, pero cambie el enfoque del recuento desigual de chunks a la distribución real del volumen de datos.
-
Obtenga información sobre la distribución de colecciones fragmentadas y el equilibrio de datos.
Use el comando
getShardDistributionpara obtener detalles de la distribución y centrarse en el equilibrio de datos. Ejemplo:mongos> db.xxx.getShardDistribution() Shard d-xxx at xxx data : 379.26MiB docs : 8277367 chunks : 1 estimated data per chunk : 379.26MiB estimated docs per chunk : 8277367 Shard d-xxx at xxx data : 379.11MiB docs : 8272852 chunks : 1 estimated data per chunk : 379.11MiB estimated docs per chunk : 8272852 Shard d-xxx at xxx data : 379.18MiB docs : 8275108 chunks : 1 estimated data per chunk : 379.18MiB estimated docs per chunk : 8275108 Totals data : 1.11GiB docs : 24825327 chunks : 3 Shard d-xxx contains 33.34% data, 33.34% docs in cluster, avg obj size on shard : 48B Shard d-xxx contains 33.32% data, 33.32% docs in cluster, avg obj size on shard : 48B Shard d-xxx contains 33.33% data, 33.33% docs in cluster, avg obj size on shard : 48BTambién puede ejecutar el siguiente comando para obtener información de distribución más detallada (incluido el recuento de documentos, el tamaño total, el recuento de documentos huérfanos y el tamaño de huérfanos):
db.getSiblingDB("admin").aggregate( [{ $shardedDataDistribution: { } },{ $match: { "ns": "<db>.<collection>" } }] ).pretty()El siguiente ejemplo de salida muestra un desequilibrio notable de datos entre los shards.
{ "ns" : "<db>.<collection>", "shards" : [ { "shardName" : "d-xxxxxxxxxxxxxxx1", "numOrphanedDocs" : 0, "numOwnedDocuments" : 504298920, "ownedSizeBytes" : NumberLong("833101815840"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx2", "numOrphanedDocs" : 0, "numOwnedDocuments" : 250283901, "ownedSizeBytes" : NumberLong("409714745937"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx3", "numOrphanedDocs" : 0, "numOwnedDocuments" : 109098088, "ownedSizeBytes" : NumberLong("178157177704"), "orphanedSizeBytes" : 0 }, { "shardName" : "d-xxxxxxxxxxxxxxx4", "numOrphanedDocs" : 0, "numOwnedDocuments" : 382018055, "ownedSizeBytes" : NumberLong("630329790750"), "orphanedSizeBytes" : 0 } ] }A partir de esta salida, puede determinar que la instancia tiene 4 nodos shard y que el volumen total de datos para la colección fragmentada
<db>.<collection>es de aproximadamente 2051303530231 bytes (833101815840 + 409714745937 + 178157177704 + 630329790750 = 2051303530231), o alrededor de 1910.4 GB. -
Consulte el volumen de datos migrados correctamente durante el último día.
Ejecute la siguiente consulta:
pipeline = [ { '$match': { 'what': 'moveChunk.commit', } }, { '$group': { '_id': { 'date': { '$dateToString': { 'format': '%Y-%m-%d', 'date': '$time'} }, }, 'chunks_moved': { '$sum': 1 }, 'docs_moved': { '$sum': '$details.counts.cloned' }, 'bytes_moved': { '$sum': '$details.counts.clonedBytes' }, } }, { '$sort': { '_id.date': -1} }, ] db.getSiblingDB("config").changelog.aggregate(pipeline)Salida de ejemplo:
mongos> db.getSiblingDB("config").changelog.aggregate(pipeline) { "_id" : { "date" : "2024-09-24" }, "chunks_moved" : 91, "docs_moved" : NumberLong(33071040), "bytes_moved" : NumberLong("11532786734") } { "_id" : { "date" : "2024-09-23" }, "chunks_moved" : 294, "docs_moved" : NumberLong(109806635), "bytes_moved" : NumberLong("38294757573") } { "_id" : { "date" : "2024-09-22" }, "chunks_moved" : 737, "docs_moved" : NumberLong(266800041), "bytes_moved" : NumberLong("93047288531") } { "_id" : { "date" : "2024-09-21" }, "chunks_moved" : 1448, "docs_moved" : NumberLong(525308393), "bytes_moved" : NumberLong("183117965820") } { "_id" : { "date" : "2024-09-20" }, "chunks_moved" : 1459, "docs_moved" : NumberLong(530020503), "bytes_moved" : NumberLong("184390749022") } { "_id" : { "date" : "2024-09-19" }, "chunks_moved" : 1478, "docs_moved" : NumberLong(557833705), "bytes_moved" : NumberLong("186910196651") } { "_id" : { "date" : "2024-09-18" }, "chunks_moved" : 1360, "docs_moved" : NumberLong(508484825), "bytes_moved" : NumberLong("173486932689") }Esta salida muestra que el
2024-09-21se migraron 183117965820 bytes (aproximadamente 170.5 GB).
Paso 4: Estimar el progreso de la tarea y el tiempo de finalización
Para versiones de MongoDB anteriores a la 6.0
Esta sección aplica a las siguientes versiones:
Instancias de MongoDB anteriores a la versión 6.0.
Instancias de MongoDB 6.0 con una versión menor del motor anterior a la 7.0.1 (versión base 6.0.3). Para consultar la versión menor de su motor, consulte MongoDB minor version guide.
Después de obtener el número de chunks migrados correctamente y la distribución actual de datos, estime el progreso general de la tarea y el tiempo esperado de finalización.
Suponga las siguientes condiciones ideales durante la adición de shards: el recuento total de chunks permanece constante, el recuento de shards se mantiene fijo (sin adiciones ni eliminaciones concurrentes de shards), la carga del servicio permanece estable y los parámetros del Balancer usan valores predeterminados. Con el ejemplo de Step 3 en Para versiones de MongoDB anteriores a la 6.0, se sabe que:
Hay 5 nodos shard.
Se migraron 300 chunks correctamente durante la ventana del Balancer.
La colección fragmentada
<db>.<collection>tiene 58260 chunks en total (13630 + 13629 + 13652 + 13630 + 3719 = 58260).
Por lo tanto, se puede calcular lo siguiente:
En equilibrio, cada shard debería contener 11652 chunks (58260 ÷ 5 = 11652).
A la tasa de migración actual, la finalización de la tarea requiere otros 26.4 días ((11652 – 3719) ÷ 300 ≈ 26.4).
La tarea de adición de shards tiene un 32 % de avance (3719 ÷ 11652 = 32 %).
En escenarios reales, el recuento total de chunks aumenta debido a escrituras continuas y divisiones de chunks. Este cálculo asume condiciones ideales; el tiempo real de finalización podría ser mayor.
Para versiones de MongoDB 6.0 y posteriores
Esta sección aplica a las siguientes versiones:
Instancias de MongoDB versión 6.0 y posteriores.
Instancias de MongoDB 6.0 con una versión menor del motor 7.0.1 (versión base 6.0.3) o posterior. Para consultar la versión menor de su motor, consulte MongoDB minor version guide.
Suponga que la instancia de clúster fragmentado tiene solo una colección que requiere balanceo. Con el ejemplo de Step 3 en Para versiones de MongoDB 6.0 y posteriores, se sabe que:
Hay 4 nodos shard.
El
2024-09-21, se migraron aproximadamente 170.5 GB (183117965820 bytes).La colección fragmentada
<db>.<collection>tiene un volumen total de datos de aproximadamente 1910.4 GB (2051303530231 bytes).
Por lo tanto, se puede calcular lo siguiente:
En equilibrio, cada shard debería contener aproximadamente 477.6 GB (512825882557.75 bytes).
-
El volumen total de datos que necesita migrarse para alcanzar el equilibrio es de 875559682949 bytes (815.4 GB), desglosado de la siguiente manera:
Shard1 necesita migrar 320275933282.25 bytes (833101815840 – 512825882557.75).
Shard2 necesita migrar 103111136620.75 bytes (409714745937 – 512825882557.75).
Shard3 necesita migrar 334668704853.75 bytes (178157177704 – 512825882557.75).
Shard4 necesita migrar 117503908192.25 bytes (630329790750 – 512825882557.75).
(320275933282.25 + 103111136620.75 + 334668704853.75 + 117503908192.25 = 875559682949)
A la tasa de migración actual, el equilibrio se alcanzará en aproximadamente 4.8 días (815.4 GB ÷ 170.5 GB/día ≈ 4.8 días).
Paso 5: Comprobar si el flujo de la tarea está bloqueado (eliminación de shard)
Si la tarea de eliminación de shard está bloqueada, la salida de sh.status() no muestra migraciones de chunks exitosas en periodos recientes, y el shard que se está eliminando todavía tiene chunks que no han migrado. En este caso, la tarea de eliminación de shard no puede completarse y otras operaciones de administración y mantenimiento en la instancia desde la consola de ApsaraDB for MongoDB también se ven afectadas.
El siguiente ejemplo muestra la salida de sh.status() en este escenario.
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Balancer lock taken at Wed Sep 30 2020 02:03:11 GMT+0800 (CST) by ConfigServer:Balancer
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "report", "primary" : "d-0xixxx", "partitioned" : true }
report.report
shard key: { "GsId" : "hashed" }
unique: false
balancing: true
chunks:
d-0xixxx 9
d-0xixxx 2133
d-0xixxx 2152
d-0xixxx 2116
d-0xixxx 2133
too many chunks to print, use verbose if you want to force print
Es probable que este problema sea causado por chunks jumbo que bloquean el proceso de eliminación del shard. Ejecute el siguiente comando para buscar chunks jumbo.
db.getSiblingDB("config").chunks.aggregate([{$match: {shard: "d-xxxxxxxxxxxxxx", jumbo:true}},{$group: {_id: "$ns", count: {$sum: 1}}}])
Los chunks jumbo suelen ser causados por un diseño inadecuado de clave de shard, como claves calientes. Antes de continuar, clasifique los chunks jumbo en una de las siguientes categorías:
Divisible: El tamaño del chunk supera
chunkSize, pero el chunk aún puede dividirse en chunks más pequeños según la clave de shard. No se requiere manejo especial. El Balancer migra el chunk después de dividirlo.No divisible: La mayoría de los datos en el chunk comparten el mismo valor de clave de shard (clave caliente). El tamaño de los datos supera
chunkSizey el chunk no puede dividirse. Utilice uno de los siguientes métodos para manejar este tipo.
Pruebe los siguientes métodos según sus requisitos empresariales:
-
Método 1: Optimizar el diseño de la clave de shard (solución raíz para problemas de claves calientes)
Para MongoDB 4.4 o posterior, utilice el comando refineCollectionShardKey para agregar campos de sufijo a la clave de shard existente. Esto aumenta la cardinalidad de la clave de shard y hace que los chunks jumbo previamente indivisibles sean divisibles.
Para MongoDB 5.0 o posterior, también puede utilizar el comando reshardCollection para volver a fragmentar la colección con una nueva clave de shard. Para obtener más información, consulte Reshard a Collection.
-
Método 2: Migrar el chunk jumbo (para MongoDB 4.4 o posterior, por ejemplo, cuando un chunk jumbo no puede migrarse durante la eliminación de un shard)
-
Opción 1 (recomendada): Ejecute el comando clearJumboFlag para borrar la marca jumbo del chunk y luego establezca el parámetro del Balancer
attemptToBalanceJumboChunksentruepara permitir que el Balancer migre automáticamente el chunk. Este método no bloquea las escrituras durante la copia de datos. Las escrituras se bloquean solo brevemente durante la etapa final de la migración.ImportanteSi el volumen de escritura en el chunk es alto, la migración puede fallar debido al desbordamiento de la caché incremental. Después del fallo, el chunk se vuelve a marcar como jumbo. Borre la marca nuevamente y reintente.
Una vez que la migración tenga éxito, establezca inmediatamente
attemptToBalanceJumboChunksde nuevo enfalse. Para MongoDB 6.0 o posterior, el Balancer equilibra basándose en las diferencias de volumen de datos entre shards. Después de que el chunk sobredimensionado se migra a cualquier shard, ese shard se convierte en el valor atípico del volumen de datos. Si no restaura la configuración, el Balancer migrará el chunk de ida y vuelta entre shards, causando transferencia continua de datos y sobrecarga por limpieza de documentos huérfanos. Después de restaurar la configuración, el chunk se vuelve a marcar como jumbo cuando falla el siguiente intento de migración regular y ya no se mueve. Esto es esperado y no requiere borrar la marca nuevamente.
Opción 2: Ejecute el comando
moveChunkcon la opciónforceJumbo: true. Este método bloquea todas las escrituras en la colección del shard origen durante la copia de datos, lo cual puede durar horas para chunks grandes. Utilice este método solo fuera de horas pico o cuando las escrituras puedan pausarse. Se recomienda realizar esta operación con asistencia del soporte técnico de Alibaba Cloud.
-
Método 3: Eliminar datos. Si algunos datos empresariales pueden eliminarse, quite datos del chunk jumbo para reducir su tamaño. Nota: Después de que el chunk se vuelve más pequeño, la marca jumbo no se borra automáticamente. Todavía debe ejecutar el comando
clearJumboFlag(o esperar hasta que el chunk se divida correctamente) antes de que el Balancer pueda migrarlo.Método 4: Aumentar el parámetro chunkSize. Aumente el parámetro
chunkSizepara cambiar el umbral de chunk jumbo. Este método es efectivo solo cuando el tamaño real del chunk excede ligeramente el umbral actual. No ayuda con chunks sobredimensionados causados por claves calientes. Se recomienda realizar esta operación con asistencia del soporte técnico de Alibaba Cloud.
Si ninguno de los métodos anteriores resuelve el problema, envíe un ticket para contactar al soporte técnico.
Acelerar los procesos de tareas de adición o eliminación
Para completar la adición o eliminación de shards más rápido, pruebe estos métodos de aceleración:
Aumente la duración de la ventana del Balancer. Tenga en cuenta que la migración de chunks agrega carga adicional que puede afectar su servicio. Evalúe los riesgos antes de ajustar. Para obtener instrucciones, consulte Manage the MongoDB Balancer.
Ajuste el parámetro setParameter.chunkMigrationConcurrency para cambiar la concurrencia de migración de chunks. Para obtener detalles, consulte Parameter tuning recommendations.
-
Ejecute manualmente operaciones
moveChunkfuera de horas pico. Para obtener más información, consulte sh.moveChunk(). Ejemplo:sh.moveChunk("<db>.<collection>", {"<shard_key>": <value>}, "d-xxxxxxxxxxxxx") // example: sh.moveChunk("records.people", { zipcode: "53187" }, "shard0019") envíe un ticket para solicitar ajustes de parámetros del kernel al soporte técnico.