User Tools

Site Tools


configuracion_de_rendimiento_de_elasticsearch

Tuning de ElasticSearch: guía para optimizar el rendimiento

Memoria RAM

Desactivar swap en el sistema.

swapoff -a
# Opcion 2: sysctl -w vm.swappiness=1

Es mejor siempre desactivar la swap completamente, ya que en determinados momentos, aunque tengamos el swappiness a 1 o 0, la swap puede ser utilizada en caso de emergencia. En cuanto al valor de swappiness, se debe evitar el 0 ya que puede provocar en algunos casos OOM-killer.

Memoria RAM de los procesos de ElasticSearch.

Variables que rigen el uso de memoria RAM de ElasticSearch, se pueden configurar en el mismo ejecutable elasticsearch.

ES_HEAP_SIZE=3g # Total de la memoria RAM utilizada por ES. (//ES_HEAP_SIZE=3g// = //ES_MIN_MEM=3g// y //ES_MAX_MEM=3g//).
# ES_MIN_MEM # Mínimo de memoria a utilizar por ES (256m por defecto).
# ES_MAX_MEM # Máximo tamaño de memoria RAM utilizada por ES (1g por defecto).
 
# Equivalente al arrancar el servicio.
./bin/elasticsearch -Xmx3g -Xms3g

No se deben utilizar servidores de más de 64Gb de memoria RAM, tampoco se recomienda de más de 30-32 Gb para configurar el ES_HEAP_SIZE. A partir de 32 Gb, java no puede comprimir oops (Leer), por lo que importa poco que se tenga un servidor con más de un 2T de memoria que estos nunca serán usados. Recordar que es posible ejecutar varias instancias si se usan diferentes ficheros de configuración, nombres y puertos.

Activar mlockall en ElasticSearch: /etc/elasticsearch/elasticsearch.yml

bootstrap.mlockall: true

No se debe usar toda la memoria ram del servidor para ElasticSearch, ya que Lucene necesita también memoria que no está definida dentro de lo que se reserva con “ES_HEAP_SIZE”. Lucene está diseñado para aprovechar el sistema operativo subyacente para las estructuras de datos de almacenamiento en memoria caché. Los Segmentos de datos de Lucene son inmutables (no cambian nunca) y se almacenan en archivos individuales, esto los hace buenos candidatos para que el SO los mantenga en memoria ram para su rápido acceso.

Por tanto, lo recomendado es darle la mitad a ES_HEAP_SIZE y la otra mitad para el sistema operativo / Lucene, si Lucene no tiene memoria el rendimiento de búsquedas de texto completo puede perjudicarse mucho. Lucene nunca dejará de llenar la memoria que tenga disponible, por lo que no hay que preocuparse de que pueda quedar ram en desuso

Cache del campo data. (Field data cache)

La cache del campo data (por defecto ilimitada), es usada cuando se realiza un facetado o se ordena una salida, cargando todos los valores de los campos en memoria. Por tanto su configuración tiene impacto sobre esas dos actividades, en mayor medida cuando se utilizan índices grandes.

Establecer un limite del 25% de ES_HEAP_SIZE par la cache de campos.

indices.fielddata.cache.size: 25%
# Definir un valor fijo.
indices.fielddata.cache.size: 12GB

Monitorización del campo data: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-nodes-stats.html

NOTA: Al crear un campo se puede definir.

Disco duro

Recomendaciones típicas.

  • Usar discos SSD (I/O Shedulers: deadline o noop).
  • No utilizar RAID 0 / NFS, SMB/CIFS y otros sistemas de ficheros en red.
  • Utilizar múltiples discos y jugar con la opción path.data de ES.
  • Cuanto más cerca estén las nodos de un clúster mejor, se deben evitar distancias geográficas amplias ya que ES trata a los nodos por igual.

Si se usan discos duros mecánicos convencionales (no SSD), se debe limitar el numero de hilos que deben acceder al disco de forma concurrente, el valor de hilos es igual al valor de “max_thread_count + 2”.

Por defecto el valor es “Math.max(1, Math.min(3, Runtime.getRuntime().availableProcessors() / 2))”, el cual debe ser para discos SSD la opción recomendada, pero si se utilizan discos no SSD, la recomendación es utilizar el valor 1.

index.merge.scheduler.max_thread_count: 1

Para tener un menor número de operaciones de entrada salida y mejores tasas de indexación, se puede incrementar el valor de index.translog.flush_threshold_size de 200 a 1GB. De esta forma el translog (donde se guardan todas las transacciones de indexación o borrado) será limpiado cuando segmentos de datos más grandes han sido creados dentro de él. Esto provoca operaciones en el disco menos frecuentes a si se trataran con segmentos de menor tamaño.

Aumentar el número de lineas que dicho translog (uno por fragmento) puede contener antes de ser limpiado, por defecto es de 5000 pero se puede cambiar por ejemplo a 30000 para escribir menos frecuentemente en disco.

index.translog.flush_threshold_ops: 50000

Es factible utilizar varios discos duros dentro de una misma instancia de ES, normalmente se usa para los datos (data) de esta forma se consigue el mismo efecto que un RAID0 mejorando mucho el rendimiento de I/O. Otra recomendación es también separar los logs, plugins etc del disco de datos, aunque no supondría un aumento del rendimiento destacable.

# Especificar diferentes directorios / puntos de montaje para almacenar los datos.
path.data: /path/to/data1,/path/to/data2 
 
# Ruta a los ficheros de logs.
path.logs: /path/to/logs
 
# Ruta a los plugins.
path.plugins: /path/to/plugins

Número de procesadores

Por norma el número de microprocesadores / núcleos es detectado por ElasticSearch automáticamente, pero puede ser útil configurarlo a medida cuando se tienen varias instancias de ElasticSearch en una misma máquina (baremetal). Las “threads pools” comentadas anteriormente se basan en ese valor para configurar sus cantidad de hilos para cada tarea. para un entornos con ElasticSearch es mejor elegir entre máquinas con muchos cores que no con muchas CPUs.

Si se tienen 8 núcleos y dos instancias de ES, se pueden utilizar “processor:4” en cada instancia.

La opción “queue_size” permite controlar el tamaño de la cola de peticiones pendientes que están pendientes de ser recogidas por algún hilo. De forma predeterminada tiene el valor -1, que indica sin límite. Cuando llega una petición y la cola está llena, la petición es cancelada.

Especificar el número de hilos (por defecto cores x 5) / Delimitar el tamaño de las colas por hilo.

curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient": { "threadpool.index.size":40 } }'
curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient": { "threadpool.index.queue_size":2000 } }'
curl -XGET 'localhost:9200/_cluster/settings'

Si se van a realizar búsquedas que usan rangos de tiempo amplios como meses y años, se recomienda aumentar también la cola de búsquedas (1000 por defecto).

curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient": { ""threadpool.search.queue_size":5000 } }'

Típico error por un tamaño de cola demasiado pequeña a la hora de indexar.

Caused by: org.elasticsearch.ElasticsearchException: Unable to execute index operation on cluster
Caused by: org.elasticsearch.common.util.concurrent.EsRejectedExecutionException: rejected execution (queue capacity 1000) on org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction$1@263666cd
at org.elasticsearch.common.util.concurrent.EsAbortPolicy.rejectedExecution(EsAbortPolicy.java:62) ~[elasticsearch-1.0.0.jar:na]

Hilos

Configurar hilos (Thread pools) / colas.

Lo que se denomina como “thread pools” viene a ser una colección de hilos en estado de espera que ejecutan las tareas almacenadas en una cola de tareas. La comunicación entre esos diferentes grupos es algo común, por ejemplo los hilos encargados de recibir información por red se comunican con los encargados de escribir dicha información en disco. Los thread pools son utilizados debido a que la creación de nuevos hilos según son necesarios es computacionalmente más costoso.

Cuando una tarea es recibida y encolada, se le asigna un hilo para que empiece a trabajar con ella, si los hilos están ocupados con diferentes tareas, las nuevas tareas se siguen encolando hasta que hilos libres puedan empezar a trabajar con ellas. ElasticSearch tiene varios grupos de hilos (thread Pools) para configurar en base al consumo de memoria dentro de un nodo. Muchas de esos grupos de hilos tienen asociadas colas de tareas.

Es importante asignar el número de hilos / límites de las colas acorde a las necesidades y recursos disponibles. El número de hilos nunca debe ser superior al número de núcleos del procesador. La configuración por defecto del grupo de subprocesos en Elasticsearch es muy sensibles. Para todos los conjuntos de subprocesos (excepto search), el número de hilos se establece en relación al número de núcleos de CPU. Si se tiene ocho núcleos, solo se pueden ejecutar ocho hilos simultáneamente.

NOTA: Subir los valores dentro de la configuración de los hilos no tiene sentido, un hilo por cada core es lo correcto si se quieren paralelizar tareas.

Tipos de Thread Pools en ES.

  • cache: Grupo de hilos ilimitado que genera hilos si hay peticiones pendientes.
  • fixed: Numero de hilos fijo para manejar las peticiones de una cola (opcionalmente delimitado) de tareas pendientes de ser procesadas.
    • Parámetro size:Número de hilos, por defecto el numero de cores x 5.
    • Parámetro queue_size: Tamaño máximo de la cola donde se almacenan tareas que todavía no han sido despachadas. si la cola está llena y se envía una petición, está será descartada.

Las Thread pools más importantes.

  • index (fixed): Operaciones de indexación / borrado de documentos. size: número de procesadores / queue_size: 200.
  • search (fixed): Contabilizar / buscar documentos. size: número de procesadores x3 / queue_size: 1000.
  • suggest (fixed): Sugerencias de búsquedas. size: número de procesadores / queue_size: 1000.
  • get (fixed): Operaciones GET. size: número de procesadores / queue_size: 1000.
  • bulk (fixed): Operaciones Bulk. size: número de procesadores / queue_size: 50.
  • percolate (fixed): operaciones de filtrado. Por defecto size: número de procesadores / queue_size: 1000.
  • snapshot (scaling): Por defecto: keep-alive: 5m, size: 1/2 número de procesadores
  • warmer (scaling): Operaciones warm-up con segmentos. Por defecto keep-alive: 5m.
  • refresh (scaling): Operaciones de refresco. Por defecto keep-alive: 5m.
  • listener: Se usa principalmente con clientes java, si “listener.threads” está activo el valor por defecto es 1/2 número de procesadores. El valor máximo a configurar es 10.

Establecer temporalmente y en todos los nodos del clúster la cantidad de hilos a ejecutar.

curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient": { "threadpool.index.size":24 } }'

Leer: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html

Indexación de documentos por lotes.

Si se utiliza la indexación por lotes de forma continua, como por ejemplo al tratar con logs, es recomendable subir el valor de la cola para no perder datos y evitar los errores de “RemoteTransportException”. En ES cada Bulk request contiene un item por shard, por lo que el número debe ser mayor que el número de peticiones concurrentes permitido.

# Numero de peticiones que pueden ser encoladas cuando no hay hilos disponibles para su tratamiento.
threadpool.bulk.queue_size: 2000 

Error que indica que se debe subir el valor.

RemoteTransportException[[<Bantam>][inet[/192.168.76.1:9300]][bulk/shard]]; nested: EsRejectedExecutionException[rejected execution (queue capacity 10) on org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction$1@13fe9be];

Priorizar entre indexación y búsquedas

Por defecto, se reserva / prioriza el 90% de la memoria RAM definida en ES para funciones de búsqueda. Si se debe tener más capacidad de indexado o bien se prefiere tener más igualado el rendimiento entre indexación (40%) y búsqueda (60%), se puede configurar la siguiente directiva.

indices.memory.index_buffer_size: 40%

ElasticSearch tiene varias colas asociadas a las que se puede ajustar su tamaño para evitar que los hilos empiecen a descartar peticiones (escritura, búsquedas, etc) bajo cargas altas. Con el comando siguiente se pueden visualizar estadísticas de uso de las colas y ver si algo falla. Aquí podrá ver los distintos valores que se pueden configurar para ajustar los hilos y colas a necesidades.

host         ip           bulk.active bulk.queue bulk.rejected index.active index.queue index.rejected search.active search.queue search.rejected 
10.0.207.18  10.0.207.18            0          0             0            0           0              0            10        23825               0 
10.0.107.64  10.0.107.64            3          0             0            0           0              0            10        24972               0 
10.0.127.92  10.0.127.92            0          0             0            0           0              0             0            0               0 
14.0.207.90  14.0.207.90            0          0             0            0           0              0            10        24968               0 
109.0.207.117 109.0.207.117           0          0             0            0           0              0            10        24539               0 
10.40.207.91  10.40.207.91            0          0             0            0           0              0             0            0               0 

Cuando Kibana muestra los errores de “Courier Fetch: XX of XX shards failed”, la cola referente a las búsquedas es la que se debe configurar (por defecto 1000). De esta manera se aplicaría el valor en caliente al nodo.

curl -XPUT http://localhost/_cluster/settings -d '{
 
"persistent" : {
 
        "threadpool.search.queue_size" : 50000
       }
}'

En el fichero /etc/elasticsearch/elasticsearch.yml puede ser configurada de la siguiente manera.

## Threadpool Settings ##

## Search pool
threadpool.search.type: fixed
threadpool.search.size: 10
threadpool.search.queue_size: 70000

# Bulk pool
threadpool.bulk.type: fixed
threadpool.bulk.size: 6
threadpool.bulk.queue_size: 100

## Index pool
threadpool.index.type: fixed
threadpool.index.size: 6
threadpool.index.queue_size: 200

Ficheros abiertos

Limites de memoria y Ficheros abiertos del sistema operativo.

El masivo uso de descriptores de ficheros abiertos se debe en gran parte al uso de búsquedas lucene y sockets a causa de la interconexión entre nodos y clientes http produce muchos sockets.

Limitar número de ficheros abiertos por un usuario y quitar el límite al máximo de memoria asignada para un usuario. Para ello se debe editar el fichero /etc/security/limits.conf o bien ejecutar los comandos “ulimit” siguientes.

elasticsearch - nofile 100000
elasticsearch - memlock unlimited

# Quitar límites al bloqueo de memoria por linea de comandos.
# ulimit -l unlimited
# ulimit -SHn 10000

Si se desea que el limite de ficheros abiertos supere a lo establecido por el kernel, se debe modificar también “sysctl fs.file-max”.

Lectura recomendada: configurar_limite_de_ficheros_abiertos

Para ejecutar ElasticSearch después de haber establecido por linea de comandos los parámetros de “ulimit”, se debe entrar desde esa misma shell a la cuenta del usuario que ejecutará ElasticSearch (comando su). Lo recomendable por tanto es definir los valores en ficheros de configuración.

pam-limits: Puede ser que se deba realizar un paso adicional si la configuración de los descriptores de ficheros no tiene efecto. Para ello se debe editar /etc/pam.d/common-session y agregar la siguiente linea.

session required pam_limits.so

Memoria Virtual

Elasticsearch utiliza un directorio mmapfs / niofs híbrido para almacenar sus índices. Los límites del sistema operativo por defecto en los recuentos de mmap son demasiado bajos y provoca excepciones de memoria. para aumentarlo se puede utilizar el siguiente comando o bien para el fichero de configuración /etc/sysctl.conf.

#Consultar el valor por defecto.
sysctl vm.max_map_count
vm.max_map_count = 65530
 
# Nuevo valor.
sysctl -w vm.max_map_count = 262144

Para establecer de manera permanente este valor, actualice la configuración en /etc/sysctl.conf.

vm.max_map_count = 262144

Configurar ElasticSearch. Es recomendable usar los parámetros configurados anteriormente también en las variables de entorno de ES.

ES_HEAP_SIZE=3g # Memoria RAM total que usará ElasticSearch
MAX_OPEN_FILES=100000 # Definido previamente con ulimit.
MAX_LOCKED_MEMORY=unlimited # Definido previamente con ulimit.
LimitMEMLOCK=infinity # Variable MAX_LOCKED_MEMORY definida como unlimited y bootstrap.mlockall: true
 
# Comprobar que /tmp no esté montado como "noexec" o bien se crea /tmp/elasticsearch.
# WORK_DIR=/tmp/elasticsearch

Comprobar configuración de descriptores de ficheros y mlockall. Ejecutar ElasticSearch con la siguiente opción y comprobar posteriormente la configuración de descriptores de ficheros.

./elasticsearch -Des.max-open-files
curl localhost:9200/_nodes/process?pretty
{
  "cluster_name" : "escluster",
  "nodes" : {
    "Fa2cY8zIQw-uGhNrAnauEw" : {
      "name" : "busi arch",
      "transport_address" : "inet[/192.1.178.55:9300]",
      "host" : "busiarch",
      "ip" : "192.168.178.50",
      "version" : "1.5.2",
      "build" : "62ff986",
      "http_address" : "inet[/192.168.1.55:9200]",
      "process" : {
        "refresh_interval_in_millis" : 1000,
        "id" : 6098,
        "max_file_descriptors" : 10000,
        "mlockall" : true
      }
    }
  }
}

Configuración de los tipos de nodos

Los nodos “clientes” con usados como batidores de carga, son también parte del clúster y pueden redirigir operaciones exactamente al nodo que contiene los datos pertinentes sin tener que consultar todos o parte de los nodos. Este tipo de nodos no almacena datos y por lo tanto no realiza operaciones de gestión de clúster.

La otra ventaja de los nodos clientes es que se encargan de las operaciones de dispersión / recopilación (como las búsquedas), aliviando por tanto de esas tareas a los nodos de datos (analizar peticiones HTTP, buscar nodos, ordenar resultados, etc.)

Configurar Nodos cliente: Para ello se deben configurar elasticsearch.yml

http.enabled: true  
master: false  
data: false  
discovery:  
  zen:
    ping:
      multicast:
        enabled: false
      unicast:
        hosts: 192.168.1.1:9300, 192.168.1.2:9300, 192.168.1.3:9300

Configurar Nodos de datos (no reciben peticiones http).

http.enabled: false 

Configurar nodos maestro dedicados.

Estos tipos de nodos tienen muy bajo consumo de recursos ya que solo se dedican a la administración del clúster y no reciben tareas de indexación o búsqueda, se recomienda tener un mínimo de tres nodos dedicados en infraestructuras en producción.

node.data: false 
node.master: true

Performance en la recuperación del cluster

Una buena configuración en cuanto a recuperaciones del clúster por motivos de mantenimiento, cortes de red, etc es en la mayoría de casos algo crucial. Una configuración de recuperación puede ahorrar mucho movimiento de fragmentos y por tanto saturación de la red. Cuando una parte del clúster no espera a la otra para empezar a reordenar los datos, es cuando se originan los porblemas, ya que cuando los otros nodos reaparecen, se debe volver a reasignar todo.

Para solucionar esto se debe dar un límite “duro” para que no empiece una recuperación de datos hasta que X número de nodos (data o master) estén presentes. En conjunto con un limite de tiempo nos otorga cierta estabilidad y procesos de recuperación de segundos y no de horas.

# El cluster no opera hasta que hay por lo menos 8 nodos activos.
gateway.recover_after_nodes: 8    
 
# Comienza la recuperación después de 5 minutos o cuando 10 nodos estén en el clúster, lo que primero ocurra.
gateway.expected_nodes: 10        
gateway.recover_after_time: 5m

NOTA: Estos parámetros se deben configurar en el fichero de configuración “elasticsearch.yml”, no se puede cambiar en caliente son las opciones del clúster.

Empezar a realocar shards únicamente si un nodo cae y no vuelve en 5 Minutos.

curl -k -XPUT http://XXX/_all/_settings -d '{  "settings" : {  "index.unassigned.node_left.delayed_timeout": "6m"  } }' 

Desde Kopf se puede detener globalmente también la realocación pulsando sobre el candado. Es muy recomendable de usar si se quieren reiniciar / actualizar nodos. Leer.

Unicast VS Multicast

En producción, multicast (opción predeterminada) debe ser desactivado para que solo se permita la comunicación mediante unicast. De esta manera se evita el riesgo de que nodos no pertenecientes al cluster se unan tras recibir un ping multicast.

Para deshabilitar multicast y dejar unicamente unicast como medio de comunicación, no es necesario definir todas las direcciones IPs en cada nodo. Vale con configurar las direcciones de los nodos maestros para que puedan obtener toda la información pertinente.

# Se debe asegurar que no está permitido ya que puede funcionar en paralelo con unicast.
discovery.zen.ping.multicast.enabled: false                  
discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]

Configuración de los Fragmentos (shards)

Asignación de fragmentos (shards allocation).

La asignación de fragmentos es el proceso por el cual se asignan los diferentes shards que forman un índice a los nodos del cluster. Esto sucede al inicio de una recuperacion del cluster tras un reinicio o desconexión de nodos, en la asignación de una réplica o al realizar un rebalanceo de fragmentos.

La directiva “cluster.routing.allocation.cluster_concurrent_rebalance” determina el número de asignaciones concurrentes que se pueden llevar a cabo, esta se debe ajustar dependiendo del hardware que se disponga.

Por defecto el valor es 2, es decir, solo 2 fragmentos pueden moverse al mismo tiempo, un valor alto puede afectar a la velocidad de indexado negativamente.

La directiva “cluster.routing.allocation.disk.threshold_enabled” cuando tiene el valor true, toma en cuenta el espacio disponible en el nodo a la hora de asignar shards.

cluster.routing.allocation.disk.threshold_enabled:true
# Si el 90% del disco está ocupado se detienen la asignacion para ese nodo.
cluster.routing.allocation.disk.watermark.low: 90%        
 
# Si el 95% del disco está lleno ES empezará a sacar fragmentos de ese nodo para reasignarlos.
cluster.routing.allocation.disk.watermark.high: 95% 

Propiedades de recuperación.

Lo mejor es probar con varios valores en base al hardware que se tenga, dejar a punto esta configuración requiere realizar varias pruebas e ir adaptando los valores.

# Cuantos shards por nodo pueden ser asignados concurrentemente en un determinado momento. Puede provocar problemas de IO.
cluster.routing.allocation.node_concurrent_recoveries:4         
 
# Número de shards que se pueden inicializar concurrentemente en un nodo.
cluster.routing.allocation.node_initial_primaries_recoveries:18 
 
# Numero de streams paralelos transferidos desde otro nodo a la hora de recuperar fragmentos.
# 4 es el valor propuesto recomendable para Amazon EC, si es con hardware local se debe subir.
indices.recovery.concurrent_streams:4 				
 
# Cuantos bytes por segundo son transferidos por segundos en dichas recuperaciones de shards, se debe adaptar al hardware.
indices.recovery.max_bytes_per_sec: 40mb

Evitar los splits brain

Un split brain se produce cuando en un cluster ES hay más de un nodo que pasa a ser “master”, esto puede ser debido a cortes en la red, apagado de ciertos servidores, etc. Como los nodos maestros son los que administran el clúster y deciden a donde, cuando y como va cada shard y su réplica, si hay más de uno, se pueden perder datos

La opción “minimum_master_nodes” previene a ES de elegir un nodo maestro mientras haya suficientes nodos maestros elegibles disponibles. Esta propiedad define una cantidad mínima de los nodos maestro elegibles que deben ser conectados entre sí con el fin de formar un clúster.

Formula: quórum = (Número de nodos que pueden ser master / 2) +1

  • 10 Nodos que pueden ser maestros → quórum 6
  • 3 Nodos maestros y 100 de datos → quórum 2

Este valor siempre debe estar configurado para un quórum (mayoría) de los nodos-maestros elegibles.

Esta directiva se puede configurar con las opciones de clúster de forma que no haya que editar todos los ficheros de configuración de todos los nodos.

PUT /_cluster/settings
{
    "persistent" : {
        "discovery.zen.minimum_master_nodes" : 2
    }
}

Las opciones pueden ser persistentes (persistent), las cuales sobrescriben los ficheros de configuración o temporales (transtient), siendo deshabilitadas después de un reinicio.

Qué opciones pueden cambiarse dinámicamente: https://www.elastic.co/guide/en/elasticsearch/reference/current/cluster-update-settings.html

Fusionar segmentos (mergen)

Un fragmento en elasticsearch es un índice Lucene, y un índice de Lucene se divide en segmentos. Los segmentos son ficheros donde los datos del índice son almacenados, estos son inmutables. Cuantos más segmentos se tengan, más lentas son las búsquedas y más memoria utilizan.

El fusionado de segmentos ayuda a tener menos número de segmentos pero esa acción requiere de mucha actividad de I/O y procesamiento de CPU. El fusionado (mergen) se realiza periódicamente en segundo plano (background) y puede coincidir que ocurra justo cuando hay una indexación en marcha. Cuando esto sucede, Elasticsearch reduce las solicitudes de indexación a un solo hilo para evitar que se generan cientos de segmentos antes de que puedan ser fusionados. Esto queda reflejado en los logs de ES con nivel INFO.

Como no se quiere que las búsquedas sean afectadas por ese procesado de fusión, estas se limitan a 20 MB/s, que está muy bien para discos no SSD pero es recomendable elevar en discos SSD a 100 - 200 Mb.

PUT /_cluster/settings
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "100mb"
    }
}

Si se está realizando una importación por lotes (Bulk) y no hay que preocuparse por el rendimiento de las búsquedas, se puede desactivar dicha limitación, permitiendo indexar todo lo rápido que el disco duro pueda.

PUT /_cluster/settings
{
    "transient" : {
        "indices.store.throttle.type" : "none" 
    }
}

Una vez se haya importado se le puede volver a dar el valor de “merge” a la directiva.

Lo anterior se refiere a discos SSD, si se dispone de discos no SSD se debe agregar la siguiente directiva al fichero de configuración “elasticsearch.yml”. Con esto se consigue reducir el número de hilos que pueden acceder a disco por cada índice. La siguiente directiva responde a la siguiente formula: max_thread_count + 2.

Limitar a 3 los hilos que puedan operar concurrentemente.

index.merge.scheduler.max_thread_count: 1

Con discos en estado sólido se puede ignorar ya que por defecto toma el valor “Math.min(3, Runtime.getRuntime().availableProcessors() / 2)”, que es el óptimo para la tecnología SSD.

Se puede modificar el límite usado para reducir esas solicitudes de indexación, fijadas para discos duros no SSD a 20 por defecto. Si se utilizan discos SSD es recomendable aumentarla más, entre 100 y 200 Mb.

Para contrarrestar operaciones de Entrada y salida que puedan provocar problemas de rendimiento es también posible configurar “index.translog.flush_threshold_size” cuyo valor por defecto es 200 Mb. Puede ser recomendable elevarlo a 1Gb, ya que al tener un valor mayor, los segmentos son fusionados y limpiados menos frecuentemente.

Reiniciar / Actualizar ElasticSearch sin afectar al clúster

Si se necesita reiniciar un nodo por una actualización o reinicio del sistema operativo, conviene dar a conocer al clúster que no realice tareas de resignación de fragmentos ya que pronto volverá a estar en linea el nodo. Con esto se evitan problemas de rendimiento al reconstruir el nuevo esquema del clúster al estar el nodo offline. Se debe proceder de la siguiente manera.

1.- Desactivar la indexación de datos cuando sea posible.

2.- Desactivar rebalanceo de shards.

PUT /_cluster/settings
{
    "transient" : {
        "cluster.routing.allocation.enable" : "none"
    }
}

3.- Apagar el servicio ElsticSearch.

POST /_cluster/nodes/_local/_shutdown

4.- Realizar la tarea de mantenimiento que se deba.

5.- Arrancar de nuevo ES y confirmas que todo funciona correctamente.

PUT /_cluster/settings
{
    "transient" : {
        "cluster.routing.allocation.enable" : "all"
    }
}

Si por ejemplo se actualizó la versión de ElasticSearch del nodo, se debe repetir el mismo proceso en cada uno de los nodos que forman parte del clúster.

Otras recomendaciones

Optimizaciones en la definición del mapping.

  • Definir cada campo correctamente (numérico, cadena, fecha, etc) y meditar si deben o no ser analizados.
  • Por defecto ES guarda el evento original en el campo “_source”, si no se necesita se recomienda desactivar.
  • Por defecto ES analiza todos los datos dentro del campo especial “_all”, si no se necesita se puede desactivar.
  • Si no se está utilizando “_source”, solo almacenar “en _store” lo necesario
  • Si se usa “_source”, no tiene sentido ingresar valores en “_stored”.
  • Si no se necesitan normas de normalización al analizar campos, se pueden desactivar (setting norms.enabled: false).
  • NOTA: El campo “_source” tiene la ventaja de que se permite usar la API update.

HTTP es más rápido que HTTPS.

Si se tienen pocos nodos, tal vez sea recomendable que el número de shards se establezca a 3 -5.

El número de fragmentos (shards) no es modificable una vez creado el índice, pero sí lo son las réplicas. Es posible empezar con indices que no contengan replicas y una vez realizada la carga, crear las réplicas, eso mejora de sobremanera el rendimiento de una indexación.

Si no se necesita tiempo real en los resultados de las búsquedas se puede configurar el valor de index.refresh_interval de cada índice en 30s (por defecto es 1s). Si se va a hacer una gran importación de documentos, esta se puede desactivar mientras dure la indexación usando el valor -1. Recordar volver a su valor original una vez terminada la indexación.

Si se usan IDs en los documentos, se recomienda usar el nativo de ES (auto-ID), de lo contrario se recomienda utilizar uno compatible con Lucene (Leer).

Debido a que muchas veces el cuello de botella es el propio cliente, se pueden paralelizar indexaciones utilizando múltiples clientes de manera simultanea.

Si el cliente usa Java, se debe considerar el uso de NodeClient.

Consultas a la API HTTP: Mejor utilizar “HTTP keep alive (HTTP/1.0)” que “HTTP chunking (HTTP/1.1)”.

Desactivar borrado de todos los índices (Seguro frente a meteduras de pata).

action.disable_delete_all_indices 

Buscar consultar lentas / registrarlas en los logs.

Por defecto slowlog no está habilitado, este tipo de registro se puede emplear para registrar consultas lentas en búsqueda y solicitudes de indexación. (Leer)

Otra recomendación importante es la de no tocar la configuración predeterminada de la máquina virtual de Java (JVM).

Como probar la configuración de ElasticSearch en base al rendimiento.

  • Probar en un solo nodo, con un único fragmento y sin réplicas.
  • Examinar el rendimiento con las opciones predeterminadas como punto de partida.
  • Las pruebas de rendimiento deben durar mínimo 30 minutos para poder evaluar el desempeño a largo plazo.
  • Modificar los valores de las opciones de configuración de uno en uno si es posible.
  • Usar herramientas como “marvel”, “top”, “iostat”, “ps”, etc. para detectar cuellos de botella.
  • Para las pruebas se recomienda usar lotes de documentos a indexar (Bulk), pero se debe tener en cuenta que lo importante de ellos no es el número de documento, si no el tamaño del fichero por lotos a indexar. Esto es debido a que son almacenados siempre en la memoria del nodo coordinador para ser procesados.

Ejemplo de Error: Unable to lock JVM memory (ENOMEM)

Causa: Mala configuración de Elasticsearch (mlockall / memlock unlimited).

 Unable to lock JVM memory (ENOMEM). This can result in part of the JVM being swapped out. Increase RLIMIT_MEMLOCK (ulimit).

Solución: Con lo mostrado anteriormente es fácil deducir esta serie de instrucciones.

### Consultar y establecer los límites del sistema para el usuario elasticsearch.

su elasticsearch --shell /bin/bash --command "ulimit -l"
64


### Crear el fichero /etc/security/limits.d/elasticsearch.conf con el siguiente contenido.

elasticsearch - nofile 262144
elasticsearch - memlock unlimited

### Comprobar los limites.

su elasticsearch --shell /bin/bash --command "ulimit -l"
unlimited


### Comprobar la configuración del parámetro mlockall  en elasticsearch.yml

bootstrap.mlockall: true


### Editar /etc/init.d/elasticsearch.

MAX_LOCKED_MEMORY=unlimited
LimitMEMLOCK=infinity


### Reiniciar Elasticsearch y comprobar.

service elasticsearch restart

curl http://elastic_node1:9200/_nodes/elastic_node1/process/?pretty

{
  "cluster_name" : "dm-log",
  "nodes" : {
    "7A_E72FPRJe44qpsaMeuTw" : {
      "name" : "elastic_node1",
      "transport_address" : "inet[80.10.220.125/80.10.220.125:9300]",
      "host" : "elastic1.dominio.com",
      "ip" : "80.10.220.125",
      "version" : "1.7.2",
      "build" : "b88f43f",
      "http_address" : "inet[/80.10.220.125:9200]",
      "attributes" : {
        "master" : "false"
      },
      "process" : {
        "refresh_interval_in_millis" : 1000,
        "id" : 29502,
        "max_file_descriptors" : 262144,
        "mlockall" : true  <-----------------  :-)
      }
    }
  }
}

Controlar los timeouts cuando se usan proxys reversos como frontend de ElasticSearch

Dependiendo de la configuración del proxy reverso que se use con elasticsearch, puede que se tengan los típicos errores de gateway o proxy timeout, algo muy habitual de ver en Kibana bajo entornos mal configurados. A continuación se muestra una configuración básica especificando las variables que se deben adaptar (en segundos). La configuración utiliza autenticación básica y HTTPS.

Elasticsearch Nginx frontend + HTTPS + Basic authentication.

server {

   listen 443 ssl;
   server_name www.dominio.com;
   client_max_body_size 999M;
   client_body_buffer_size 1M;
   ####### SSL.
   ssl_certificate /etc/nginx/fichero.cer;
   ssl_certificate_key /etc/nginx/fichero.key;
   access_log off;

      location / {
       auth_basic           "ElasticSearch Cluster.";
       auth_basic_user_file /etc/nginx/usuarios;       # Autenticación HTTP.
       proxy_pass  http://127.0.0.1:9200;              # Configuración del proxy + timeouts.
       proxy_max_temp_file_size 0;
       proxy_redirect off;
       proxy_connect_timeout       300;
       proxy_send_timeout          300;
       proxy_read_timeout          300;
       send_timeout                300;
      }
  }

Enlaces de interés:

configuracion_de_rendimiento_de_elasticsearch.txt · Last modified: 2020/12/25 22:57 by 127.0.0.1