Cómo evitar explosiones de mapeo y optimizar shards en clústeres de logs

Gestionar clústeres de Elasticsearch a gran escala sin un control estricto del esquema garantiza fallos críticos de memoria y degradación del rendimiento. Los logs con estructuras JSON arbitrarias consumen recursos de heap de forma masiva si permites que el motor cree campos sin restricciones.

Implementar políticas de mapeo estricto y dimensionar correctamente los shards reduce los costos de infraestructura y estabiliza los tiempos de respuesta de búsqueda.

En resumen — Controla el crecimiento del clúster limitando el número de campos mediante plantillas de índice y manteniendo el tamaño de los shards entre 20GB y 50GB para optimizar el uso de Heap y la velocidad de I/O.

1. Qué es una explosión de mapeo

💡 Analogía: Imagina una biblioteca donde cada libro nuevo que llega obliga al bibliotecario a crear una categoría única en el catálogo. Si llegan 10,000 libros con temas ligeramente diferentes, el catálogo se vuelve tan grande que el bibliotecario ya no tiene espacio en su escritorio para consultarlo y colapsa.

En Elasticsearch, el Mapping Explosion ocurre cuando el número de campos únicos en un índice supera la capacidad de gestión de la memoria RAM (Heap) del nodo maestro. Cada campo nuevo requiere metadatos que deben sincronizarse en todo el clúster. En versiones actuales como 8.15.x, el límite predeterminado es de 1,000 campos por índice, pero en entornos de logs sin control, este límite se alcanza rápidamente.

El problema principal es el "Cluster State". Si permites que cada log de una aplicación microservicios genere sus propios campos dinámicos (por ejemplo, usando IDs únicos como nombres de campos), el estado del clúster crece exponencialmente, ralentizando cualquier operación de actualización y provocando fallos Out Of Memory (OOM).

2. Cuándo ocurre el desbordamiento de campos

Detectarás este problema principalmente en clústeres que ingieren logs de aplicaciones con formatos inconsistentes. Cuando un desarrollador añade un objeto JSON anidado profundo o utiliza claves dinámicas basadas en variables de usuario, Elasticsearch intenta mapear cada clave como un campo nuevo con su propio tipo de datos.

Otro escenario crítico es la falta de normalización en la ingesta. Si diferentes equipos envían el mismo dato con nombres ligeramente distintos (ej. `user_id`, `userId`, `user.id`), el índice acumula redundancia técnica que multiplica el uso de memoria innecesariamente. Esto es especialmente peligroso cuando el clúster gestiona cientos de índices diarios.

3. Guía de implementación de control de mapeo

Debes pasar de un modelo de "confianza ciega" a uno de "esquema bajo demanda" utilizando plantillas de índice (Index Templates).

Paso 1. Configurar una plantilla de índice estricta

Define explícitamente qué campos son permitidos y desactiva la creación automática de campos desconocidos. Esto obliga a los equipos a definir su esquema antes de enviar datos basura.

PUT _index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "template": {
    "mappings": {
      "dynamic": "strict",
      "properties": {
        "@timestamp": { "type": "date" },
        "service_name": { "type": "keyword" },
        "message": { "type": "text" },
        "level": { "type": "keyword" }
      }
    }
  }
}

Paso 2. Implementar Campos de Runtime para flexibilidad

Si necesitas permitir campos nuevos sin romper la ingesta ni inflar los metadatos, utiliza `runtime_fields`. Estos campos se calculan durante la búsqueda y no se indexan físicamente, evitando la explosión de mapeo.

PUT logs-app-001/_mapping
{
  "runtime": {
    "extra_info": {
      "type": "keyword",
      "script": {
        "source": "emit(params['_source']['temporary_field'])"
      }
    }
  }
}

Paso 3. Optimización del tamaño de Shards con ILM

Un error común es tener shards demasiado pequeños (pocos MB) o gigantescos (más de 100GB). Configura una política de Index Lifecycle Management (ILM) para realizar un `rollover` basado en el tamaño físico.

PUT _ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "40gb",
            "max_age": "1d"
          }
        }
      }
    }
  }
}

4. Dynamic vs. Strict vs. Runtime

Elegir la estrategia adecuada depende del equilibrio entre flexibilidad y estabilidad del clúster.

CriterioDynamic (Default)Strict (Recomendado)Runtime Fields
Rendimiento BúsquedaAltoMáximoBajo (calculado en query)
Riesgo de OOMCríticoMínimoBajo
Uso de DiscoAltoOptimizadoNulo
FlexibilidadTotalBajaMedia-Alta

Si tu prioridad es la estabilidad de producción, usa Strict para campos CORE y Runtime para experimentos o campos de baja frecuencia.

5. Errores comunes y Troubleshooting

⚠️ Error frecuente: Aumentar el límite `index.mapping.total_fields.limit` a valores superiores a 5,000 sin aumentar la RAM del nodo maestro suele terminar en un clúster bloqueado.

El incremento de este límite es solo un parche temporal. La solución real siempre es la normalización de los datos en la capa de ingesta (Logstash o Ingest Pipelines).

Solución por mensaje de error

Error: "Limit of total fields [1000] has been exceeded"
Causa: Intento de indexar un documento con claves nuevas no definidas.
Solución: 
1. Identificar el documento basura: GET _cluster/pending_tasks
2. Usar "dynamic": "false" en el mapeo para ignorar campos nuevos sin rechazar el documento.

6. Consejos para la gestión de shards

Mantén un ratio de shards saludable para evitar el "Over-sharding". Una regla de oro es no superar los 20 shards por cada GB de memoria Heap asignada al nodo.

Para clústeres de logs, el tamaño ideal de shard oscila entre 20GB y 50GB. Shards más pequeños fragmentan el sistema de archivos y aumentan el overhead de búsqueda; shards más grandes dificultan la recuperación ante fallos y los movimientos de datos entre nodos.

📌 Puntos clave

  • Usa dynamic: strict para forzar un esquema de datos limpio en producción.
  • Aplica ILM para garantizar que los shards se mantengan en el rango de 20GB-40GB.
  • Monitorea el estado del clúster buscando el crecimiento del Cluster State.

Preguntas frecuentes

Q. ¿Qué pasa si excedo el límite de campos?

A. Elasticsearch rechazará nuevos documentos y lanzará un error 400 Bad Request.

Q. ¿Es mejor muchos shards pequeños o pocos grandes?

A. Pocos grandes (20-50GB) para logs es lo ideal para evitar latencia.

Q. ¿Puedo cambiar el mapeo de un campo existente?

A. No directamente. Debes crear un índice nuevo y usar la API _reindex.

Post a Comment