ElasticSearch: fragmentos no asignados, ¿cómo solucionarlo?




sharding master (13)

Tengo un clúster de ES con 4 nodos:

number_of_replicas: 1
search01 - master: false, data: false
search02 - master: true, data: true
search03 - master: false, data: true
search04 - master: false, data: true

Tuve que reiniciar search03, y cuando volvió, se volvió a unir al clúster sin problemas, pero dejó 7 fragmentos sin asignar.

{
  "cluster_name" : "tweedle",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 4,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 15,
  "active_shards" : 23,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 7
}

Ahora mi clúster está en estado amarillo. ¿Cuál es la mejor manera de resolver este problema?

  • Eliminar (cancelar) los fragmentos?
  • Mueva los fragmentos a otro nodo?
  • ¿Asignar los fragmentos al nodo?
  • Actualizar 'number_of_replicas' a 2?
  • ¿Algo más completamente?

Curiosamente, cuando se agregó un nuevo índice, ese nodo comenzó a trabajar en él y jugó bien con el resto del clúster, simplemente dejó los fragmentos no asignados por ahí.

Siga con la pregunta: ¿estoy haciendo algo mal para que esto suceda en primer lugar? No tengo mucha confianza en un clúster que se comporta de esta manera cuando se reinicia un nodo.

NOTA: Si está ejecutando un clúster de nodo único por alguna razón, puede que necesite hacer lo siguiente:

curl -XPUT 'localhost:9200/_settings' -d '
{
    "index" : {
        "number_of_replicas" : 0
    }
}'

De forma predeterminada, Elasticsearch volverá a asignar fragmentos a los nodos de forma dinámica. Sin embargo, si ha deshabilitado la asignación de fragmentos (quizás reinició sucesivamente y olvidó volver a habilitarlos), puede volver a habilitar la asignación de fragmentos.

# v0.90.x and earlier
curl -XPUT 'localhost:9200/_settings' -d '{
    "index.routing.allocation.disable_allocation": false
}'

# v1.0+
curl -XPUT 'localhost:9200/_cluster/settings' -d '{
    "transient" : {
        "cluster.routing.allocation.enable" : "all"
    }
}'

Elasticsearch luego reasignará los fragmentos de forma normal. Esto puede ser lento; considere aumentar los indices.recovery.max_bytes_per_sec y cluster.routing.allocation.node_concurrent_recoveries para acelerarlo.

Si sigues teniendo problemas, probablemente haya algún otro error, así que busca en los registros de Elasticsearch los errores. Si ve EsRejectedExecutionException sus grupos de subprocesos pueden ser demasiado pequeños .

Finalmente, puede reasignar explícitamente un fragmento a un nodo con la API de redireccionamiento .

# Suppose shard 4 of index "my-index" is unassigned, so you want to
# assign it to node search03:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{
    "commands": [{
        "allocate": {
            "index": "my-index",
            "shard": 4,
            "node": "search03",
            "allow_primary": 1
        }
    }]
}'

Elasticsearch asigna automáticamente fragmentos si la configuración siguiente está establecida en todos. Esta configuración se puede establecer usando una API de reposo también cluster.routing.allocation.enable: all

Si incluso después de la aplicación de la configuración siguiente, falla en asignar los fragmentos automáticamente, entonces usted debe forzar la asignación de los fragmentos por su cuenta. ES enlace oficial para esto

He escrito una secuencia de comandos para forzar la asignación de todos los fragmentos no asignados en el clúster.

below array contiene una lista de nodos entre los que desea equilibrar los fragmentos no asignados

#!/bin/bash
array=( node1 node2 node3 )
node_counter=0
length=${#array[@]}
IFS=$'\n'
for line in $(curl -s 'http://127.0.0.1:9200/_cat/shards'|  fgrep UNASSIGNED); do
    INDEX=$(echo $line | (awk '{print $1}'))
    SHARD=$(echo $line | (awk '{print $2}'))
    NODE=${array[$node_counter]}
    echo $NODE
    curl -XPOST 'http://127.0.0.1:9200/_cluster/reroute' -d '{
        "commands": [
        {
            "allocate": {
                "index": "'$INDEX'",
                "shard": '$SHARD',
                "node": "'$NODE'",
                "allow_primary": true
            }
        }
        ]
    }'
    node_counter=$(((node_counter)%length +1))
done

En mi caso, se alcanzó el límite superior del espacio en el disco duro.

Mira este artículo: https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html

Básicamente, corrí:

PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "90%",
    "cluster.routing.allocation.disk.watermark.high": "95%",
    "cluster.info.update.interval": "1m"
  }
}

Para que se asigne si se utiliza <90% de espacio en el disco duro y mueva un fragmento a otra máquina en el clúster si se usa> 95% de espacio en el disco duro; y comprueba cada 1 minuto.


En mi caso, un antiguo nodo con acciones antiguas se unía al clúster, por lo que tuvimos que cerrar el nodo anterior y eliminar los índices con fragmentos no asignados.


Este pequeño script bash reasignará fuerza bruta, puede perder datos.

NODE="YOUR NODE NAME"
IFS=$'\n'
for line in $(curl -s 'localhost:9200/_cat/shards' | fgrep UNASSIGNED); do
  INDEX=$(echo $line | (awk '{print $1}'))
  SHARD=$(echo $line | (awk '{print $2}'))

  curl -XPOST 'localhost:9200/_cluster/reroute' -d '{
     "commands": [
        {
            "allocate": {
                "index": "'$INDEX'",
                "shard": '$SHARD',
                "node": "'$NODE'",
                "allow_primary": true
          }
        }
    ]
  }'
done

Hoy me he quedado con el mismo problema de asignación de fragmentos. El guión que ha propuesto en su respuesta no me funcionó, así que lo modifiqué un poco y finalmente funcionó:

#!/usr/bin/env bash

# The script performs force relocation of all unassigned shards, 
# of all indices to a specified node (NODE variable)

ES_HOST="<elasticsearch host>"
NODE="<node name>"

curl ${ES_HOST}:9200/_cat/shards > shards
grep "UNASSIGNED" shards > unassigned_shards

while read LINE; do
  IFS=" " read -r -a ARRAY <<< "$LINE"
  INDEX=${ARRAY[0]}
  SHARD=${ARRAY[1]}

  echo "Relocating:"
  echo "Index: ${INDEX}"
  echo "Shard: ${SHARD}"
  echo "To node: ${NODE}"

  curl -s -XPOST "${ES_HOST}:9200/_cluster/reroute" -d "{
    \"commands\": [
       {
         \"allocate\": {
           \"index\": \"${INDEX}\",
           \"shard\": ${SHARD},
           \"node\": \"${NODE}\",
           \"allow_primary\": true
         }
       }
     ]
  }"; echo
  echo "------------------------------"
done <unassigned_shards

rm shards
rm unassigned_shards

exit 0

Ahora, no soy un gurú de Bash, pero el guión realmente funcionó para mi caso. Tenga en cuenta que necesitará especificar los valores apropiados para las variables "ES_HOST" y "NODE".


Lo único que funcionó para mí fue cambiar number_of_replicas (tenía 2 réplicas, así que lo cambié a 1 y luego volví a cambiar a 2).

Primero:

PUT /myindex/_settings
{
    "index" : {
        "number_of_replicas" : 1
     }
}

Entonces:

PUT /myindex/_settings
{
    "index" : {
        "number_of_replicas" : 2
     }
}

(Ya lo asentí en esta pregunta )


Me encontré con exactamente el mismo problema. Esto se puede evitar estableciendo temporalmente la asignación de fragmento en falso antes de reiniciar elasticsearch, pero esto no soluciona los fragmentos no asignados si ya están allí.

En mi caso, fue causado por la falta de espacio libre en el disco en el nodo de datos. Los fragmentos sin asignar permanecen en el nodo de datos después del reinicio, pero no son reconocidos por el maestro.

Simplemente limpiando 1 de los nodos del disco se inició el proceso de replicación. Este es un proceso bastante lento porque todos los datos deben ser copiados de 1 nodo de datos a otro.


Otra posible razón para los fragmentos no asignados es que su clúster ejecuta más de una versión del binario de Elasticsearch.

La replicación de fragmentos desde la versión más reciente a las versiones anteriores no funcionará

Esta puede ser la causa raíz de los fragmentos no asignados.

Elastic Documentation - Rolling Upgrade Process


Para mí, esto se resolvió ejecutando esto desde la consola de desarrollo: "POST / _cluster / reroute? Retry_failed"

.....

Empecé mirando la lista de índices para ver qué índices eran rojos y luego corrí

"obtener /_cat/shards?h=[INDEXNAME],shard,prirep,state,unassigned.reason"

y vio que tenía fragmentos atrapados en el estado ALLOCATION_FAILED, por lo que ejecutar el reintento anterior provocó que volvieran a intentar la asignación.


Probé varias de las sugerencias anteriores y desafortunadamente ninguna funcionó. Tenemos un índice "Log" en nuestro entorno más bajo donde las aplicaciones escriben sus errores. Es un clúster de nodo único. Lo que me solucionó fue comprobar el archivo de configuración YML para el nodo y ver que todavía tenía la configuración predeterminada "gateway.expected_nodes: 2". Esto estaba anulando cualquier otra configuración que teníamos. Siempre que creáramos un índice en este nodo, trataríamos de esparcir 3 de 5 fragmentos al segundo nodo fantasma. Por lo tanto, estos aparecerían como no asignados y nunca podrían moverse al primer y único nodo.

La solución era editar la configuración, cambiando la configuración "gateway.expected_nodes" a 1, por lo que dejaría de buscar su hermano nunca encontrado en el clúster y reiniciar la instancia de servicio Elastic. Además, tuve que eliminar el índice y crear uno nuevo. Después de crear el índice, todos los fragmentos aparecieron en el primer y único nodo, y ninguno fue desasignado.

# Set how many nodes are expected in this cluster. Once these N nodes
# are up (and recover_after_nodes is met), begin recovery process immediately
# (without waiting for recover_after_time to expire):
#
# gateway.expected_nodes: 2
gateway.expected_nodes: 1

Tal vez ayuda a alguien, pero tuve el mismo problema y fue debido a la falta de espacio de almacenamiento causado por un tronco que se está volviendo demasiado grande.

Espero que ayude a alguien! :)


Tuve el mismo problema, pero la causa principal fue la diferencia en los números de versión (1.4.2 en dos nodos (con problemas) y 1.4.4 en dos nodos (ok)). La primera y la segunda respuesta (estableciendo "index.routing.allocation.disable_allocation" en falso y estableciendo "cluster.routing.allocation.enable" en "all") no funcionó.

Sin embargo, la respuesta de @Wilfred Hughes (estableciendo "cluster.routing.allocation.enable" en "all" usando transient) me dio un error con la siguiente declaración:

[NO (versión del nodo de destino [1.4.2] es anterior a la versión del nodo de origen [1.4.4])]

Después de actualizar los nodos antiguos a 1.4.4, estos nodos comenzaron a sincronizarse con los otros nodos buenos.