Mejores Prácticas para Gestionar y Reducir el Uso de Espacio en Disco de MongoDB
Optimiza el uso del disco de MongoDB con esta guía completa de mejores prácticas. Aprende estrategias efectivas para compactar colecciones e índices, identificar y eliminar índices innecesarios, y aprovechar las funciones de compresión de WiredTiger. Descubre cómo implementar el archivado de datos, gestionar el tamaño del oplog y monitorear proactivamente el espacio en disco para evitar interrupciones del sistema y mejorar el rendimiento. Este artículo proporciona información práctica y ejemplos concretos para mantener tus implementaciones de MongoDB ligeras y eficientes.
Mejores Prácticas para Gestionar y Reducir el Uso de Espacio en Disco de MongoDB
El uso del disco de MongoDB suele volverse urgente en el peor momento posible: un trabajo por lotes se ejecuta más de lo esperado, las eliminaciones no parecen liberar espacio, o un miembro de un conjunto de réplicas comienza a advertir que el volumen está casi lleno. La solución rara vez es un solo comando mágico. Necesitas saber si el espacio son datos activos, índices, espacio reutilizable de WiredTiger, oplog, registros o copias de seguridad locales.
El enfoque más seguro es medir primero, reducir lo que ya no necesita existir, y solo entonces ejecutar un mantenimiento más pesado como la compactación o la reconstrucción de miembros. Ese orden evita que crees un evento de mantenimiento largo que devuelva poco espacio.
Comprendiendo el Consumo de Espacio en Disco de MongoDB
MongoDB utiliza espacio en disco para varios componentes:
- Archivos de Datos: Almacena los documentos BSON reales dentro de las colecciones.
- Archivos de Índices: Almacena índices de árbol B creados para soportar la ejecución eficiente de consultas.
- Archivos de Diario (WiredTiger): Registra las operaciones de escritura antes de que se apliquen a los archivos de datos, asegurando la durabilidad de los datos. Estos están preasignados.
- Oplog (Registro Operacional): Una colección limitada especial en conjuntos de réplicas que registra todas las operaciones de escritura. Esencial para la replicación.
- Datos de Diagnóstico: Registros, archivos de proceso
mongody otra información relacionada con el sistema.
Con el tiempo, debido a actualizaciones, eliminaciones y crecimiento de documentos (relleno), las colecciones y los índices pueden fragmentarse o contener espacio asignado no utilizado, lo que lleva a un uso ineficiente del disco. Este "espacio en blanco" no es reclamado inmediatamente por el sistema operativo, incluso si la base de datos ya no lo necesita para datos activos.
Estrategias para Reducir el Espacio en Disco de MongoDB
1. Compactación de Colecciones e Índices
Las operaciones de compactación ayudan a recuperar espacio en disco no utilizado reescribiendo los archivos de datos e índices de manera más eficiente. Esto puede ser particularmente útil después de eliminaciones o actualizaciones significativas de datos.
Compactación de Colecciones
Con el motor de almacenamiento WiredTiger (predeterminado desde MongoDB 3.2), compact recupera principalmente espacio libre de documentos eliminados y desfragmenta colecciones. No reconstruye el archivo de datos de la colección desde cero como lo hacía la operación compact de MMAPv1.
db.runCommand({ compact: "myCollection" })
Consideraciones para compact:
- Las operaciones
compactpueden consumir muchos recursos (CPU, E/S) y llevar una cantidad significativa de tiempo, especialmente para colecciones grandes. A menudo es mejor ejecutarlas durante ventanas de mantenimiento o en miembros secundarios de un conjunto de réplicas. - Los requisitos de disco y el comportamiento de bloqueo varían según la versión de MongoDB, el motor de almacenamiento y la forma de implementación. Consulta la documentación de tu versión exacta antes de ejecutarlo en una colección de producción grande.
- Para clústeres fragmentados, ejecuta
compacten cada fragmento de forma independiente.
Reconstrucción de Índices
Los índices también pueden fragmentarse. Reconstruir un índice puede recuperar espacio y potencialmente mejorar el rendimiento de las consultas.
db.myCollection.reIndex()
Consideraciones de reIndex():
- El comportamiento de
reIndex()ha cambiado entre versiones de MongoDB y aún puede ser disruptivo en sistemas ocupados. Consulta el manual para tu versión, pruébalo en un entorno de prueba y, cuando sea posible, prefiere trabajar de forma continua a través de los miembros del conjunto de réplicas. - Similar a
compact,reIndex()requiere espacio en disco adicional durante la operación.
repairDatabase (Operación Fuera de Línea)
Para fragmentación severa o corrupción de datos, repairDatabase puede reconstruir todos los archivos de datos. Esta es una operación fuera de línea y requiere detener la instancia de mongod.
mongod --repair
Advertencia: repairDatabase debe usarse como último recurso para la recuperación de espacio, ya que es una operación destructiva si no se maneja con cuidado y puede llevar mucho tiempo. Siempre ten una copia de seguridad.
2. Optimización de Índices
Los índices son cruciales para el rendimiento, pero pueden consumir un espacio de disco significativo. Los índices no utilizados o redundantes son pura sobrecarga.
Identificación y Eliminación de Índices Innecesarios
Revisa regularmente tus índices para asegurarte de que aún sean necesarios.
- Lista todos los índices de una colección:
db.myCollection.getIndexes()
```
2. Monitorea el uso de índices: Usa $indexStats, planes de consulta, perfiles y el historial de carga de trabajo de tu aplicación. Las estadísticas de colección muestran el tamaño del índice, pero no prueban si un índice es útil.
3. Identifica índices duplicados o redundantes: Por ejemplo, un índice en { a: 1, b: 1 } hace que un índice en { a: 1 } sea redundante para consultas que pueden usar el índice compuesto. Un índice en { a: 1, b: 1 } también está cubierto por un índice en { a: 1, b: 1, c: 1 } para consultas que solo involucran a y b.
Una vez identificado, elimina el índice no utilizado:
db.myCollection.dropIndex("indexName")
Consejo: Siempre prueba el impacto de eliminar un índice en un entorno de prueba antes de aplicarlo a producción.
Uso de Índices Parciales
Los índices parciales solo indexan documentos en una colección que cumplen con una expresión de filtro especificada. Esto reduce la cantidad de documentos indexados, ahorrando espacio en disco y mejorando el rendimiento de escritura.
db.orders.createIndex(
{ customerId: 1, orderDate: -1 },
{ partialFilterExpression: { status: "active" } }
)
Este índice solo incluiría documentos donde status sea "active", reduciendo su tamaño si la mayoría de los pedidos son históricos, cancelados, archivados o están fuera de la ruta activa. La parte importante no es la palabra "active"; es el hábito de indexar el subconjunto que tu aplicación consulta realmente todos los días.
Comienza con un Triage de Espacio en Disco, No con un Comando de Limpieza
Cuando el espacio en disco de MongoDB está creciendo, el primer error es saltar directamente a compact, repair o eliminar datos antiguos. Esas acciones pueden ayudar, pero también pueden crear carga, tomar bloqueos en algunas situaciones u ocultar el problema real durante unas semanas. Comienza respondiendo tres preguntas:
- ¿Qué sistema de archivos se está llenando: la ruta de la base de datos, la ruta del diario, la ruta de registros o el volumen de copia de seguridad?
- ¿Están creciendo los datos activos, o está creciendo el espacio asignado pero no utilizado después de eliminaciones y actualizaciones?
- ¿El crecimiento proviene de colecciones, índices, el oplog, registros, datos de diagnóstico o instantáneas?
Una primera pasada rápida generalmente se ve así:
df -h
du -h --max-depth=1 /var/lib/mongodb | sort -h
du -h --max-depth=1 /var/log/mongodb | sort -h
Luego verifica MongoDB desde el shell:
db.adminCommand({ listDatabases: 1 })
db.getSiblingDB("app").stats()
db.getSiblingDB("app").orders.stats()
storageSize, totalIndexSize y dataSize cuentan historias diferentes. Si dataSize está creciendo, probablemente tengas un problema de ciclo de vida de datos. Si storageSize es mucho mayor que dataSize, es posible que estés viendo espacio interno reutilizable después de eliminaciones. Si totalIndexSize es grande en comparación con dataSize, el diseño de índices merece atención antes de que toques la compactación.
Comprende lo que MongoDB Puede y No Puede Devolver
Con WiredTiger, eliminar documentos generalmente hace que el espacio esté disponible para su reutilización por MongoDB. No siempre devuelve ese espacio al sistema operativo de inmediato. Ese comportamiento sorprende a las personas durante la limpieza de emergencia: eliminan un lote grande, ejecutan df -h y ven casi ninguna mejora.
Eso no significa que la eliminación haya fallado. Significa que MongoDB a menudo puede reutilizar ese espacio para futuras inserciones y actualizaciones. Si el objetivo es detener el crecimiento, eliminar o archivar datos antiguos puede ser suficiente. Si el objetivo es reducir el sistema de archivos porque el volumen está casi lleno o el host se está reduciendo, es posible que necesites compactación, resincronización de un miembro del conjunto de réplicas, o una reconstrucción estilo dump-and-restore.
Para sistemas de producción, generalmente separo el trabajo en dos vías. La primera vía es la seguridad inmediata: agregar disco, eliminar la acumulación obvia de registros, pausar trabajos por lotes riesgosos o mover las copias de seguridad fuera del volumen de la base de datos. La segunda vía es la reducción real: corregir la retención, eliminar índices no utilizados y reconstruir el almacenamiento solo después de saber dónde se fueron los bytes.
Corrige la Retención de Datos Antes de Desfragmentar Cualquier Cosa
Si tu aplicación conserva registros de solicitudes, eventos, sesiones, notificaciones, registros de trabajos o documentos de análisis para siempre, el uso del disco regresará sin importar cuán cuidadosamente compactes. MongoDB te ofrece algunas opciones prácticas.
Para datos que caducan con una marca de tiempo simple, un índice TTL suele ser la respuesta más limpia:
db.sessions.createIndex(
{ expiresAt: 1 },
{ expireAfterSeconds: 0 }
)
Ese índice elimina documentos después de la fecha almacenada en expiresAt. Es útil para sesiones, tokens temporales, trabajos de importación de corta duración o respuestas de API en caché. No es un reemplazo para las reglas de retención comerciales. El monitor TTL se ejecuta en segundo plano, por lo que no esperes una eliminación segundo a segundo, y no uses TTL en datos que requieran un flujo de trabajo de aprobación antes de la eliminación.
Para registros comerciales, archiva en lugar de eliminar ciegamente. Un patrón común es:
- Copiar documentos más antiguos que la ventana de retención a un almacenamiento más barato o una base de datos de archivo.
- Verificar recuentos y una muestra de campos importantes.
- Eliminar en lotes pequeños de la colección principal.
- Observar el retraso de replicación y las métricas de disco mientras se ejecuta el trabajo.
Los lotes pequeños importan. Una sola eliminación grande puede crear presión de replicación, llenar registros y dificultar la reversión si alguien se da cuenta de que el filtro era incorrecto. Un trabajo por lotes más seguro podría eliminar unos pocos miles de documentos a la vez, dormir brevemente y registrar el progreso por _id o marca de tiempo.
while (true) {
const result = db.events.deleteMany({
createdAt: { $lt: ISODate("2025-01-01T00:00:00Z") },
archived: true
});
print(`deleted ${result.deletedCount}`);
if (result.deletedCount === 0) break;
sleep(500);
}
En un script de producción real, agrega un patrón de límite en lugar de deleteMany sobre todo el rango, registra cada lote y detente automáticamente si el retraso de replicación o la E/S del disco cruzan tu umbral.
Ten Cuidado con los Consejos sobre Índices que Suenan Demasiado Simples
Eliminar índices no utilizados es una de las mejores maneras de reducir el espacio en disco de MongoDB, pero "no utilizado" necesita contexto. Un índice puede parecer no utilizado durante una semana tranquila y seguir siendo crítico para informes de fin de mes, conciliación en segundo plano o un flujo de trabajo de soporte al cliente poco común.
Usa $indexStats para ver los patrones de acceso:
db.orders.aggregate([{ $indexStats: {} }])
Luego compara el resultado con el código de la aplicación, trabajos programados, paneles y consultas de soporte. Si un índice no se ha utilizado desde el último reinicio, eso es una señal, no un veredicto. Antes de eliminarlo, verifica si el servidor se reinició recientemente y si la muestra de carga de trabajo incluye los trabajos que importan.
También presta atención a los índices compuestos superpuestos. Si tienes estos:
{ customerId: 1 }
{ customerId: 1, createdAt: -1 }
{ customerId: 1, createdAt: -1, status: 1 }
puede que puedas eliminar uno, pero solo después de verificar el orden de clasificación, los filtros de consulta y si el índice más corto admite un patrón de acceso diferente. MongoDB puede usar el prefijo izquierdo de un índice compuesto, pero eso no significa que el índice más grande sea siempre un reemplazo gratuito. Los índices más grandes cuestan más memoria y E/S de escritura, así que conserva el que se ajuste a la carga de trabajo, no el que se vea más completo.
Prefiere la Resincronización para Grandes Operaciones de Reducción en Conjuntos de Réplicas
Para un conjunto de réplicas grande, la forma más limpia de recuperar espacio en disco del sistema operativo suele ser reconstruir un secundario a la vez. La idea básica es:
- Confirmar que tienes replicación saludable y copias de seguridad actuales.
- Eliminar o detener un secundario.
- Limpiar su directorio de datos local.
- Dejarlo resincronizar desde el primario u otro miembro saludable.
- Repetir para el siguiente secundario.
- Degradar el primario durante una ventana de mantenimiento y reconstruir el antiguo primario al final.
Este enfoque es más lento que ejecutar un comando, pero es más fácil de razonar porque cada miembro reconstruido escribe archivos de almacenamiento nuevos basados en los datos actuales. También evita intentar compactar cada colección bajo tráfico de producción. No es gratuito: la sincronización inicial puede ser intensiva en red y disco, y necesitas suficientes miembros restantes para mantener seguro el conjunto de réplicas mientras un miembro se está reconstruyendo.
Para un servidor MongoDB independiente, no tienes ese lujo. En ese caso, planifica una ventana de mantenimiento, toma una copia de seguridad probada y considera mongodump/mongorestore o una migración a nivel de sistema de archivos a un volumen nuevo. No elijas mongod --repair solo porque quieres un directorio de datos más pequeño. Trata la reparación como una herramienta de recuperación, no como un mantenimiento rutinario.
Vigila También el Oplog, los Registros y las Copias de Seguridad
No toda la presión del disco de MongoDB proviene de las colecciones. En los conjuntos de réplicas, el oplog es una colección limitada, por lo que no debería crecer para siempre, pero su tamaño configurado aún importa. Si es demasiado pequeño, los secundarios pueden quedarse atrás durante el mantenimiento. Si es mucho más grande de lo necesario en un disco pequeño, puede estar desperdiciando espacio. Revísalo deliberadamente:
db.getSiblingDB("local").oplog.rs.stats()
Los registros de MongoDB también pueden llenar un disco cuando el registro de consultas lentas, la verbosidad de depuración o un bucle de error de aplicación se vuelven ruidosos. Usa la rotación de registros y mantén los registros de la base de datos alejados del mismo volumen pequeño que almacena los datos siempre que sea posible.
Las copias de seguridad son otra sorpresa común. Los equipos a veces ejecutan mongodump en el mismo host porque es conveniente, y luego se preguntan por qué las alertas de disco se activan durante la ventana de copia de seguridad. Una copia de seguridad almacenada en el mismo sistema de archivos no es realmente una copia de seguridad, y puede empujar a MongoDB a una interrupción peor durante una operación ya riesgosa. Transmite las copias de seguridad a un almacenamiento de objetos, un servidor de copias de seguridad o un volumen montado separado.
Un Manual Práctico para un Disco de MongoDB Lleno
Si el disco ya está por encima del 90 por ciento, reduce la velocidad y trabaja en este orden:
- Confirmar si MongoDB todavía acepta escrituras y si el conjunto de réplicas está saludable.
- Agregar capacidad de disco temporal si la plataforma lo permite. Esto suele ser más seguro que la eliminación de emergencia.
- Mover o rotar registros de gran tamaño y archivos de copia de seguridad locales.
- Detener trabajos por lotes no esenciales que estén escribiendo intensamente.
- Identificar las colecciones e índices más grandes con
db.stats()ystats()de colección. - Archivar o eliminar solo datos con una regla de retención clara.
- Planificar compactación, resincronización o restauración después de que el sistema esté estable.
La mejor solución a largo plazo es aburrida: reglas de retención, revisiones de índices, alertas de disco y procedimientos de reconstrucción probados. MongoDB se siente cómodo reutilizando el espacio libre interno, pero los operadores aún deben decidir qué datos merecen vivir en almacenamiento rápido y qué puede moverse a otro lugar.