Dec 21st, 2021: [es] Tres recomendaciones para tener un clúster Elasticsearch saludable

This article is also available in English:

https://discuss.elastic.co/t/289326

En nuestro día a día de soporte en Elastic vemos algunas herramientas que son muy útiles cuando necesitamos ayudar a nuestros clientes a solucionar problemas en sus clústeres de Elasticsearch o monitorizar para mantenerlos saludables. Repasemos las 3 principales con algunos ejemplos.

1. Conoce tus APIs REST

Conocer las APIs REST de Elasticsearch es muy útil para manter el clúster en buen estado. No solo ayudan a solucionar problemas, sino también a prevenirlos. Si se desea algo más legible para personas, empezaremos echando un vistazo a las CAT APIs.

El primer paso para mantener el clúster en buen estado es mantenerlo en verde. Con una simple llamada a la API de cluster health:

GET /_cluster/health

Obtendremos una descripción general del estado de nuestro clúster.

{
  "cluster_name": "eyeveebee-prod-cluster",
  "status": "red",
  "timed_out": false,
  "number_of_nodes": 30,
  "number_of_data_nodes": 27,
  "active_primary_shards": 15537,
  "active_shards": 26087,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 1,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 209,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 235940,
  "active_shards_percent_as_number": 99.99616762873977
}

En el ejemplo, tenemos un clúster en rojo. Podemos ver que tenemos un shard sin asignar, lo que hace que el estado del clúster sea rojo. El estado de un clúster es el del peor shard del peor índice. Por lo tanto, al menos algun índice o shard estarán en rojo.

Es importante mantener el clúster en verde. Las alertas de Kibana pueden ayudarnos notificándonos cuando el clúster se vuelve amarillo (falta al menos una replica de un shard) o rojo (falta al menos un shard primario).

Para investigar cual es el índice que está en rojo, podemos usar el CAT indices API:

GET _cat/indices?v&s=health:desc,index&h=health,status,index,docs.count,pri,rep

Así localizaremos el índice rojo.

health status index                    docs.count pri rep
red    open   eventlogs-000007                      1   1
green  open   .apm-agent-configuration          0   1   1
...

Con CAT shards API podemos bajar a nivel de shard en el índice ‘eventlogs-000007’:

GET /_cat/shards?v&s=state:asc,node,index&h=index,shard,prirep,state,docs,node

Para ver que efectivamente tiene su shard primario en estado ‘UNASSIGNED’, no asignado.

index                                                                 shard prirep state         docs node
eventlogs-000007                                                      0     p      UNASSIGNED         
.apm-agent-configuration                                              0     p      STARTED          0 instance-0000000012
...

Finalmente podemos usar Cluster Allocation explain API para llegar al motivo:

GET _cluster/allocation/explain
{
  "index": "eventlogs-000007",
  "shard": 0,
  "primary": true
}

Obtendríamos una explicación similar a la siguiente, que debería permitirnos llegar a la causa raíz.

{
  "index" : "eventlogs-000007",
  "shard" : 0,
  "primary" : false,
  "current_state" : "unassigned",
  "unassigned_info" : {
    "reason" : "NODE_LEFT",
    "at" : "2021-12-08T17:00:53.596Z",
    "details" : "node_left [gyv9cseHQyWD-FjLTfSnvA]",
    "last_allocation_status" : "no_attempt"
  },
  "can_allocate" : "no",
  "allocate_explanation" : "cannot allocate because allocation is not permitted to any of the nodes",
  "node_allocation_decisions" : [
    {
      "node_id" : "-PYVqLCLTSKjriA6UZthuw",
      "node_name" : "instance-0000000012",
      "transport_address" : "10.43.1.6:19294",
      "node_attributes" : {
        "xpack.installed" : "true",
        "data" : "hot",
        "transform.node" : "true"
      },
      "node_decision" : "no",
      "deciders" : [
        {
          "decider" : "same_shard",
          "decision" : "NO",
          "explanation" : "the node is above the high watermark cluster setting [cluster.routing.allocation.disk.watermark.high=90.0%], having less than the minimum required [90.0%] free space, actual free: [9.13%]"
        }
      ]
    },
    ...

En este caso, nos hemos quedado sin almacenamiento en nuestros nodos y no se pueden asignar shards. Algo que podríamos acabar de confirmar si quisiéramos utilizando CAT allocation API.

Podemos prevenir llegar al watermark de disco con Kibana alerts for disk usage threshold. Si mantenemos nuestros nodos alrededor del 75% de almacenamiento, tendremos colchón para crecer y mantener el clúster estable. A partir del 85% de almacenamiento utilizado (valor por defecto), tendremos limitaciones de asignación de shards.

No podemos enfatizar lo suficiente la importancia de planificar la retención de datos. Index Lifecycle Management y el uso de Data Tiers nos serán de gran ayuda para mantener el almacenamiento controlado. Muy recomendable leer la documentacion sobre el tamaño de los shards, punto que es clave para mantener el clúster en estado óptimo.

No olvidemos tampoco los snapshots de Elasticsearch, con su snapshot lifecycle-management, que nos permite estar preparados para escenarios de pérdida de datos. Asimismo configurar para configurar para alta disponibilidad.

También observamos, en el estado del clúster del ejemplo, que la cantidad de tareas pendientes es algo elevada. De nuevo el uso de CAT APIs, en este caso CAT pending tasks API, para revisar que tareas tenemos pendientes:

GET /_cat/pending_tasks?v
insertOrder timeInQueue priority source 
412717 5.2s NORMAL restore_snapshot[2021.12.17-.ds-logs-2021.12.09-000030-trdkfuewwkjaca] 
412718 2s NORMAL ilm-execute-cluster-state-steps [{"phase":"cold","action":"searchable_snapshot","name":"wait-for-index-color"} => {"phase":"cold","action":"searchable_snapshot","name":"copy-execution-state"}]
...
...

O podríamos usar jq para agregar los resultados de pending cluster tasks API de forma que podamos investigar más facilmente qué tipo de tareas tenemos pendientes.

curl --silent --compressed  'https://localhost:9200/_cluster/pending_tasks' | jq '.tasks[].source' -cMr  | sed -e 's/[.*//' | sort | uniq -c

Esto nos daría una idea más clara de estas tareas agrupadas:

  1 restore_snapshot
 17 delete-index
183 ilm-execute-cluster-state-steps
  2 node-join
  4 update task state
  2 update-settings

Esto es solo para mostrar que, conociendo las API REST disponibles, podemos obtener información muy útil para evaluar el estado de nuestro clúster y ajustar nuestra arquitectura en consecuencia.

Para terminar esta sección, recomiendo echar un vistazo a Elastic’s support diagnostics. Esas son las llamadas a las API REST que utilizamos en Elastic Support para ayudar a nuestros clientes a mantener sus clústeres en buen estado. O al blog “Why does Elastic support keep asking for diagnostic files” que explica porque pedimos este diagnóstico.

2. Sacarle partido al Monitoring y Alertas del Stack Elastic

La segunda recomendación es disponer de un clúster de monitorización dedicado para entornos productivos. Las API REST nos brindan información en el moento, pero nos faltan los datos históricos. Si lo enviamos a un clúster de monitorización dedicado, nos ayudará a investigar incidentes, capacity planning, etc.

Kibana alerts for the Elatic Stack monitoring nos notificará de potenciales problemas.

Un caso que vemos a menudos en soporte de Elastic, donde los datos de monitorización son útiles, es el hotspotting de nodos.

Si tenemos un clúster que presenta una CPU elevada, por ejemplo, durante la ingesta, en uno o solo algunos de los nodos de datos, mientras que los otros están inactivos; y esos nodos siguen cambiando. Podemos usar el monitoreo para confirmar nuestras sospechas.

Echemos un vistazo al UI de Kibana Stack Monitoring para nuestro clúster. De los 3 nodos que tenemos, sólo uno muestra un uso alto de CPU.

Podríamos investigar más yendo a la pestaña de índices. En este caso, encontramos que durante la ventana en la que vemos un alto uso de CPU en un nodo, tenemos un índice, ‘log-201998’, que tiene una tasa de ingesta muy alta en comparación con el resto.

Si este índice tiene un shard primario y es el único con una tasa de ingesta alta, podríamos asignar 3 shards primarios en vez de 1, por lo que la carga se equilibraría entre las 3 instancias de datos que tenemos en este ejemplo.

Para clústeres más grandes y con más de un índice “hot”, la situación podría no ser tan sencilla. Es posible que se requiera limitar la cantidad de fragmentos para esos índices que terminan en cada nodo del clúster. Consulte nuestra documentación evitar hotspots en nodos.

Tener un clúster de monitoring será de gran ayuda.

3. Revisar logs proactivamente

Una última recomendación es revisar los logs de forma proactiva.

Podemos usar el módulo de Filebeat para Elasticsearch para ingestar nuestros logs en el clúster de monitoring que acabamos de comentar. O incluso usar las capacidades del stack de categorización de logs para descubrir comportamientos anómalos y generar alertas asociadas.

Un ejemplo que vemos a menudo con nuestros clientes es el mapeo de tipo de datos incorrecto en algunos índices.

Dependiendo de cómo configuremos los mappings en nuestros índices, es posible que estemos perdiendo documentos que provocan un conflicto de tipos. Si revisamos los registros de nuestro clúster, veríamos esos errores y podríamos actuar.

Tomemos el ejemplo de un documento que a veces tiene un valor numérico en la fuente que lo envía y, a veces, es alfanumérico. Si usamos los mapeos dinámicos predeterminadas en vez de explícitos, y primero ingerimos este documento con un valor numérico de un campo, lo llamaremos “key”:

POST my-test-index/_doc
{
  "key": 0
}

Elasticsearch interpretará este campo como un número, de tipo long.

GET my-test-index/_mapping/field/key
{
  "my-test-index" : {
    "mappings" : {
      "key" : {
        "full_name" : "key",
        "mapping" : {
          "key" : {
            "type" : "long"
          }
        }
      }
    }
  }
}

I si el siguiente documento lleva en este campo, por poner un ejemplo, un UUID:

POST my-test-index/_doc
{
  "key": "123e4567-e89b-12d3-a456-426614174000"
}

En Kibana Dev Tools veríamos el error.

{
  "error" : {
    "root_cause" : [
      {
        "type" : "mapper_parsing_exception",
        "reason" : "failed to parse field [key] of type [long] in document with id '4Wtyz30BtaU7QP7QuSQY'. Preview of field's value: '123e4567-e89b-12d3-a456-426614174000'"
      }
    ],
    "type" : "mapper_parsing_exception",
    "reason" : "failed to parse field [key] of type [long] in document with id '4Wtyz30BtaU7QP7QuSQY'. Preview of field's value: '123e4567-e89b-12d3-a456-426614174000'",
    "caused_by" : {
      "type" : "illegal_argument_exception",
      "reason" : "For input string: "123e4567-e89b-12d3-a456-426614174000""
    }
  },
  "status" : 400
}

Este código 400 es un error no recuperable y significa que Elasticsearch no indexará el documento y los clientes como Logstash o Agent no volverán a intentarlo.

Si buscamos nuestros documentos en el índice, solo tenemos el primero.

GET my-test-index/_search?filter_path=hits.total,hits.hits._source
{
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "hits" : [
      {
        "_source" : {
          "key" : 0
        }
      }
    ]
  }
}

Esto que vemos en Kibana, también aparecería en nuestros logs. Es muy habitual que encontremos esto en Logstash (registros que también podemos ingerir usando el módulo Logstash de Filebeat). Podría pasar desapercibido a menos que revisemos nuestros registros.

Could not index event to Elasticsearch. {:status=>400, :action=>["index", {:_id=>nil, :_index=>"my-test-index-0000001", :routing=>nil, :_type=>"_doc"}, #<LogStash::Event:0x5662a9f3>], :response=>{"index"=>{"_index"=>"my-test-index-0000001", "_type"=>"_doc", "_id"=>"Qmt6z30BtaU7QP7Q4SXE", "status"=>400, "error"=>{"type"=>"mapper_parsing_exception", "reason"=>"failed to parse field [key] of type [long] in document with id 'Qmt6z30BtaU7QP7Q4SXE'

Adicionalmente, si ingestamos logs, estaremos preparados para revisar los slow logs en el caso que necesitemos resolver algun problema relacionado con lentitud de búsquedas o de ingesta.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.