Agregar un nuevo shard es el método estándar para escalar horizontalmente un clúster con sharding de MongoDB. Sin embargo, los datos no siempre se redistribuyen automáticamente; el nuevo shard puede permanecer inactivo mientras los shards antiguos continúan bajo presión. Este tema describe un proceso sistemático para diagnosticar por qué no se equilibran los datos y resolver el desbalance.
Funcionamiento del equilibrio de datos
El equilibrio de datos entre shards depende exclusivamente del balancer integrado de MongoDB. El balancer redistribuye los datos mediante la migración de chunks desde los shards sobrecargados hacia los que tienen menor carga. Si el balancer no se está ejecutando, tiene una configuración incorrecta o está bloqueado por las propiedades de la colección, los chunks permanecen en su ubicación original.
El proceso de diagnóstico consta de dos niveles:
Estado del balancer: compruebe que el balancer esté habilitado, activo y ejecutándose dentro de una ventana válida.
Viabilidad de migración de datos: identifique las propiedades de la colección que impiden al balancer mover datos, como colecciones sin sharding, volúmenes de datos inferiores al umbral de equilibrio o la presencia de jumbo chunks.
Diagnóstico del estado del balancer
El balancer es el único mecanismo para la migración de chunks. Comience por aquí antes de investigar cualquier otro aspecto.
Comprobar si el balancer está habilitado
En mongosh, ejecute:
sh.getBalancerState()
Si el resultado es false, el balancer está deshabilitado. Habilítelo siguiendo los pasos en Manage the MongoDB balancer.
Verificar la ventana activa
El balancer solo se ejecuta durante su ventana activa configurada. Si la hora actual queda fuera de esa ventana, no se realiza ninguna migración.
Ejecute el siguiente comando para revisar la configuración de la ventana activa:
db.getSiblingDB("config").settings.find({_id:"balancer"})
Ejemplo de salida:
{ _id: 'balancer', activeWindow: { start: '02:00', stop: '04:00' } }
Si la ventana es demasiado corta o se superpone con las horas de mayor tráfico, amplíela para abarcar un periodo más largo de baja demanda. El siguiente ejemplo establece la ventana de 02:00 a 06:00 diariamente:
db.getSiblingDB("config").settings.updateOne(
{ _id: "balancer" },
{ $set: { activeWindow: { start: "02:00", stop: "06:00" } } },
{ upsert: true }
)
Comprobar si el equilibrio ya está en curso
Después de agregar un shard, el balancer necesita tiempo para migrar los datos existentes. Es normal que exista un desequilibrio durante este periodo.
Ejecute el siguiente comando para verificar si hay una tarea de migración activa:
sh.isBalancerRunning()
Si el resultado es true, el equilibrio está en curso. Espere a que finalice. Para seguir el progreso, consulte How to check the progress of adding or removing a shard node.
Análisis de la viabilidad de migración de datos
Si el balancer está habilitado y en ejecución, pero los datos no se mueven, es probable que el problema resida en las propiedades de la colección. Las siguientes condiciones pueden bloquear la migración.
Buscar colecciones grandes sin sharding
Una base de datos puede contener colecciones con y sin sharding. Las colecciones sin sharding almacenan todos sus datos en el shard principal de la base de datos, por lo que el balancer no puede migrar esta información. Si sus colecciones más grandes no tienen sharding, nunca llegarán al nuevo shard.
Ejecute el siguiente script para calcular cuánto almacenamiento ocupan las colecciones sin sharding en una base de datos específica:
// Replace "myDB" with the name of the database to check
var dbName = "myDB";
var unshardSize = 0;
var totalSize = 0;
var unshardedCollections = [];
db.getSiblingDB(dbName).getCollectionNames().forEach(function(collName) {
var stats = db.getSiblingDB(dbName).getCollection(collName).stats();
// Check the stats.sharded field and add up the storage size
if (!stats.sharded) {
unshardSize += (stats.storageSize || 0);
unshardedCollections.push(dbName + "." + collName);
}
totalSize += (stats.storageSize || 0);
// Sleep briefly after each query to avoid excessive load on the database
sleep(200);
});
print("--- " + dbName + " ---");
print("Unsharded Collections Count: " + unshardedCollections.length);
print("--------------------");
print("Unsharded Storage Size (Bytes): " + unshardSize);
print("Total Storage Size (Bytes): " + totalSize);
print("--------------------");
print("Unsharded Collections List:");
printjson(unshardedCollections);
Este script llama astats()en cada colección, lo cual puede afectar el rendimiento de la base de datos. El retraso integrado desleep(200)reduce este riesgo. Para bases de datos con muchas colecciones, aumente el retraso a2000o más.
Si las colecciones sin sharding representan una parte significativa del almacenamiento, habilite el sharding en ellas. Para obtener instrucciones, consulte Set up data sharding to fully utilize shard performance.
Comprobar si las colecciones con sharding están por debajo del umbral de migración (MongoDB 6.0+)
A partir de MongoDB 6.0.3, el balancer solo migra chunks cuando la diferencia en el volumen de datos entre shards para una colección determinada alcanza un umbral específico. El umbral predeterminado es tres veces el tamaño del chunk.
Con el tamaño de chunk predeterminado de 128 MB, el desequilibrio de datos entre dos shards debe alcanzar como mínimo 384 MB antes de que el balancer inicie la migración para esa colección. Las colecciones con un volumen total de datos inferior a este umbral se consideran equilibradas y no se modifican.
Para comprobar cómo se distribuyen los datos de una colección entre los shards, ejecute:
db.<collection>.getShardDistribution()
Si la mayor parte de los datos de una colección con sharding se concentra en un solo shard y el desequilibrio es inferior a 384 MB (con el tamaño de chunk predeterminado), el balancer no actuará. Reduzca el valor de chunkSize de la colección para disminuir el umbral y desencadenar la migración:
// This example sets chunkSize to 16 MB for test_db.test_coll.
// Adjust chunkSize based on your collection's data volume and distribution.
db.adminCommand({
configureCollectionBalancing: "test_db.test_coll",
chunkSize: 16 // Unit: MB. Default for MongoDB 6.0+: 128 MB
})
Una vez completada la migración, compruebe que la distribución haya mejorado:
db.<collection>.getShardDistribution()
Consideraciones de rendimiento y configuración
Sobrecarga de rendimiento por el equilibrio
La migración de chunks (moveChunk) y la posterior eliminación de rangos (RangeDeleter) consumen CPU y E/S de disco tanto en los shards de origen como en los de destino. Para evitar afectar el tráfico en línea, establezca la ventana activa del balancer en horarios de baja demanda.
Riesgo de configuración de chunkSize (versiones de MongoDB anteriores a la 6.0)
En versiones de MongoDB anteriores a la 6.0, establecer chunkSize en un valor demasiado pequeño puede generar una cantidad excesiva de chunks. Esto incrementa la sobrecarga de metadatos en el servidor de configuración y provoca que el balancer se ejecute con demasiada frecuencia. Establezca chunkSize según el volumen total de datos y la tasa de crecimiento esperada de la colección.