ElasticSearch: Shards non attribués, comment réparer?

166

J'ai un cluster ES avec 4 nœuds:

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

J'ai dû redémarrer search03, et quand il est revenu, il a rejoint le cluster sans problème, mais a laissé 7 fragments non attribués.

{
  "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
}

Maintenant, mon cluster est à l'état jaune. Quelle est la meilleure façon de résoudre ce problème?

  • Supprimer (annuler) les fragments?
  • Déplacer les fragments vers un autre nœud?
  • Allouer les fragments au nœud?
  • Mettre à jour 'number_of_replicas' à 2?
  • Quelque chose d'autre entièrement?

Fait intéressant, lorsqu'un nouvel index a été ajouté, ce nœud a commencé à travailler dessus et a bien joué avec le reste du cluster, il a juste laissé les fragments non attribués traîner.

Suivez la question: est-ce que je fais quelque chose de mal pour que cela se produise en premier lieu? Je n'ai pas beaucoup confiance dans un cluster qui se comporte de cette façon lorsqu'un nœud est redémarré.

REMARQUE: Si vous exécutez un cluster à nœud unique pour une raison quelconque, vous devrez peut-être simplement effectuer les opérations suivantes:

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

Réponses:

118

Par défaut, Elasticsearch réattribuera dynamiquement les fragments aux nœuds. Cependant, si vous avez désactivé l'allocation de partition (peut-être avez-vous effectué un redémarrage progressif et oublié de la réactiver), vous pouvez réactiver l'allocation de partition.

# 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 réaffectera ensuite les fragments comme d'habitude. Cela peut être lent, pensez à augmenter indices.recovery.max_bytes_per_secetcluster.routing.allocation.node_concurrent_recoveries à l'accélérer.

Si vous rencontrez toujours des problèmes, quelque chose d'autre ne va probablement pas, alors regardez dans vos journaux Elasticsearch les erreurs. Si vous voyez que EsRejectedExecutionExceptionvos pools de threads sont peut-être trop petits .

Enfin, vous pouvez réaffecter explicitement une partition à un nœud avec l' API de redirection .

# 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
        }
    }]
}'
Wilfred Hughes
la source
3
Quand j'ai fait cela, j'ai obtenu: { "error" : "ElasticsearchIllegalArgumentException[[allocate] failed to find [logstash-2015.01.05][1] on the list of unassigned shards]", "status" : 400 } même si je peux voir que ce fragment est l'un des non alloués dans ES-Head
wjimenez5271
Incidemment, d'autres fragments ont fonctionné qui étaient répertoriés comme non alloués, puis les autres se sont corrigés.
wjimenez5271
c'est un excellent conseil.
Yehosef
1
Depuis la version 5.0, la commande "allocate" a changé pour fournir plus d'options - l'exemple ci-dessus serait maintenant "allocate_empty_primary", en omettant le paramètre "allow_primary".
jmb
4
vous devez ajouter -H 'Content-Type: application/json'si vous obtenez l'erreurContent-Type header [application/x-www-form-urlencoded] is not supported
luckydonald
57

OK, j'ai résolu ce problème avec l'aide du support ES. Exécutez la commande suivante à l'API sur tous les nœuds (ou les nœuds que vous pensez être la cause du problème):

curl -XPUT 'localhost:9200/<index>/_settings' \
    -d '{"index.routing.allocation.disable_allocation": false}'

<index>est l'index que vous croyez être le coupable. Si vous n'avez aucune idée, exécutez simplement ceci sur tous les nœuds:

curl -XPUT 'localhost:9200/_settings' \
    -d '{"index.routing.allocation.disable_allocation": false}'

J'ai également ajouté cette ligne à ma configuration yaml et depuis lors, tout redémarrage du serveur / service s'est déroulé sans problème. Les fragments ré-alloués immédiatement.

FWIW, pour répondre à une question souvent recherchée, définissez MAX_HEAP_SIZE sur 30G à moins que votre machine ne dispose de moins de 60G de RAM, auquel cas réglez-la sur la moitié de la mémoire disponible.

Références

Spanky
la source
2
pour résoudre ce problème dans la version 1.1.1, dois-je utiliser cluster.routing.allocation.enable = none?
user3175226
1
La désactivation de l'allocation n'y est plus documentée, du moins pas à partir du 20 novembre
3
Notez que l'allocation de routage est un paramètre à l'échelle du cluster, donc peu importe le nœud auquel vous envoyez la commande.
Wilfred Hughes
J'ai ajouté les deux dans mon fichier es yml. index.routing.allocation.disable_allocation : false cluster.routing.allocation.enable: noneMais les fragments non attribués sont toujours affichés. Quelle peut en être la raison?
bagui
1
Dans la version 6.8 j'obtiens une erreur:{ "type": "illegal_argument_exception", "reason": "unknown setting [index.routing.allocation.disable_allocation] please check that any required plugins are installed, or check the breaking changes documentation for removed settings" } ],
Janac Meena le
39

Ce petit script bash sera réaffecté par force brute, vous risquez de perdre des données.

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
W. Andrew Loe III
la source
A travaillé comme un charme. Merci!
Paulo Pires
J'ai eu cette erreur: <br> {"error": "JsonParseException [Caractère inattendu r (',' (code 44)): attendu une valeur valide (nombre, chaîne, tableau, objet, 'true', 'false' ou 'null') \ n à [Source: [B @ 3b1fadfb; ligne: 6, colonne: 27]] "," status ": 500} <br> que dois-je faire pour y remédier
biolinh
Merci beaucoup! Cela a permis de gagner un temps précieux !!
Sathish
Le script jette l'erreur:{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}{"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}
Janac Meena
17

La seule chose qui a fonctionné pour moi a été de changer le number_of_replicas (j'avais 2 répliques, donc je l'ai changé en 1 puis je suis revenu à 2).

Première:

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

Ensuite:

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

(J'y ai déjà répondu dans cette question )

Edi
la source
9

Elasticsearch alloue automatiquement des fragments si la configuration ci-dessous est définie sur tous. Cette configuration peut être définie à l'aide d'une API de repos ainsi que cluster.routing.allocation.enable: all

Si même après l'application de la configuration ci-dessous, es ne parvient pas à attribuer automatiquement les fragments, vous devez forcer l'assignation des fragments vous-même. Lien officiel ES pour cela

J'ai écrit un script pour forcer l'affectation de toutes les partitions non attribuées à travers le cluster.

Le tableau ci-dessous contient la liste des nœuds parmi lesquels vous souhaitez équilibrer les fragments non attribués

#!/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
Nischal Kumar
la source
Ce script ne fonctionnait pas, c'est-à-dire qu'après l'avoir exécuté, j'avais toujours des fragments NON ASSIGNÉS.
Chris F
@ChrisF En ligne1: vous devez remplacer node1, node2, node3 par les noms de nœuds réels. Vous pouvez les obtenir avec un localhost curl: 9200 / _cat / nodes.
sidi
6

Je suis resté aujourd'hui avec le même problème d'allocation des fragments. Le script que W.Andrew Loe III a proposé dans sa réponse ne fonctionnait pas pour moi, je l'ai donc modifié un peu et cela a finalement fonctionné:

#!/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

Maintenant, je ne suis pas en quelque sorte un gourou de Bash, mais le script a vraiment fonctionné pour mon cas. Notez que vous devrez spécifier les valeurs appropriées pour les variables "ES_HOST" et "NODE".

Splanger
la source
malheureusement l'ES5x a cassé la compatibilité: élastique.co
guide/en
2
Pour que le script ci-dessus fonctionne avec ES5x, remplacez allocatepar allocate_empty_primaryet remplacez \"allow_primary\": truepar\"accept_data_loss\": true
Fawix
Se {"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406}venger après avoir appliqué la suggestion de
Fawix
6

Dans mon cas, la limite supérieure de l'espace disque dur a été atteinte.

Regardez cet article: https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html

En gros, j'ai couru:

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

Pour qu'il alloue si <90% d'espace disque dur utilisé, et déplace une partition vers une autre machine du cluster si> 95% d'espace disque dur utilisé; et il vérifie toutes les 1 minute.

plusieurs façons
la source
4

Peut-être que cela aide quelqu'un, mais j'ai eu le même problème et c'était dû à un manque d'espace de stockage causé par un journal qui devenait trop gros.

J'espère que cela aide quelqu'un! :)

Juanjo Lainez Reche
la source
4

Dans mon cas, lorsque je crée un nouvel index, le number_of_replicas par défaut est défini sur 1. Et le nombre de nœuds dans mon cluster était un seul, il n'y avait donc pas de nœud supplémentaire pour créer le réplica, donc la santé devenait jaune. Donc, quand j'ai créé l'index avec la propriété settings et que j'ai défini le number_of_replicas sur 0. Ensuite, cela a bien fonctionné. J'espère que cela t'aides.

PUT /customer
{
    "settings": {
        "number_of_replicas": 0
    }
}
Apoorv Nag
la source
3

J'ai eu le même problème mais la cause première était une différence dans les numéros de version (1.4.2 sur deux nœuds (avec des problèmes) et 1.4.4 sur deux nœuds (ok)). Les première et deuxième réponses (définir «index.routing.allocation.disable_allocation» sur false et «cluster.routing.allocation.enable» sur «all») ne fonctionnaient pas.

Cependant, la réponse de @Wilfred Hughes (définir "cluster.routing.allocation.enable" sur "all" en utilisant transitoire) m'a donné une erreur avec l'instruction suivante:

[NON (la version du nœud cible [1.4.2] est antérieure à la version du nœud source [1.4.4])]

Après avoir mis à jour les anciens nœuds vers la version 1.4.4, ces nœuds ont commencé à se résigner avec les autres bons nœuds.

Jörg Rech
la source
3

J'avais également ce problème et j'ai trouvé un moyen simple de le résoudre.

  • Obtenez l'index des fragments non attribués

    $ curl -XGET http://172.16.4.140:9200/_cat/shards
    
  • Installez les outils de conservation et utilisez-les pour supprimer l'index

    $ curator --host 172.16.4.140 delete indices --older-than 1 \
           --timestring '%Y.%m.%d' --time-unit days --prefix logstash
    

    REMARQUE: dans mon cas, l'index est logstash du jour 2016-04-21

  • Ensuite, vérifiez à nouveau les fragments, tous les fragments non attribués disparaissent!
user3391471
la source
1
@sim, merci beaucoup pour votre modification pour ma réponse. Je suis très pauvre en édition, j'y prêterai plus d'attention.
user3391471
Pour moi, c'était:curator_cli --host 127.0.0.1 delete_indices --filter_list '[{"filtertype":"pattern","kind":"prefix","value":"logstash-"}]'
Gaui
2

Je rencontre également cette situation et je l'ai finalement corrigée.

Tout d'abord, je décrirai ma situation. J'ai deux nœuds dans le cluster ElasticSearch, ils peuvent se trouver, mais lorsque j'ai créé un index avec les paramètres "number_of_replicas": 2 , "number_of_shards": 5, ES affiche un signal jaune et unassigned_shards est 5.

Le problème se produit parce que la valeur de number_of_replicas , lorsque je mets sa valeur à 1 , tout va bien.

Armstrongya
la source
4
Le nombre de répliques doit toujours être N-1 le nombre de nœuds que vous avez. Donc, dans votre scénario avec 2 nœuds, 1 des nœuds contient la partition principale, tandis que l'autre nœud a la réplique, donc votre nombre de répliques doit être défini sur 1. N = 2, N - 1 = 1.
slm
1

Dans mon cas, un ancien nœud avec d'anciens partages rejoignait le cluster, nous avons donc dû arrêter l'ancien nœud et supprimer les index avec des fragments non attribués.

alwe
la source
1

J'ai essayé plusieurs des suggestions ci-dessus et malheureusement aucune d'elles n'a fonctionné. Nous avons un index «Log» dans notre environnement inférieur où les applications écrivent leurs erreurs. Il s'agit d'un cluster à nœud unique. Ce qui l'a résolu pour moi a été de vérifier le fichier de configuration YML pour le nœud et de voir qu'il avait toujours le paramètre par défaut "gateway.expected_nodes: 2". Cela remplaçait tous les autres paramètres que nous avions. Chaque fois que nous créerions un index sur ce nœud, nous essayions de diffuser 3 fragments sur 5 sur le 2ème nœud fantôme. Ceux-ci apparaîtront donc comme non attribués et ne pourront jamais être déplacés vers le 1er et unique nœud.

La solution était de modifier la configuration, de changer le paramètre "gateway.expected_nodes" sur 1, afin qu'il cesse de rechercher son frère introuvable dans le cluster et de redémarrer l'instance de service Elastic. De plus, j'ai dû supprimer l'index et en créer un nouveau. Après avoir créé l'index, les fragments sont tous apparus sur le premier et unique nœud, et aucun n'a été désattribué.

# 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
Daniel Knowlton
la source
1

Pour moi, cela a été résolu en exécutant ceci à partir de la console de développement: "POST / _cluster / reroute? Retry_failed"

.....

J'ai commencé par regarder la liste d'index pour voir quels index étaient rouges puis j'ai couru

"get /_cat/shards?h=[INDEXNAME[/), hard,prirep,state,unassigned.reason"

et a vu qu'il y avait des fragments bloqués dans l'état ALLOCATION_FAILED, donc l'exécution de la nouvelle tentative ci-dessus les a obligés à réessayer l'allocation.

ScottFoster1000
la source
À partir de la version 5.6.3, la commande devrait être get /_cat
shards
0

Cela pourrait aider, mais j'ai eu ce problème en essayant d'exécuter ES en mode intégré. Le correctif consistait à s'assurer que le nœud avait un ensemble local (vrai).

JARC
la source
0

Une autre raison possible pour les fragments non attribués est que votre cluster exécute plusieurs versions du binaire Elasticsearch.

La réplication de partition de la version la plus récente vers les versions précédentes ne fonctionnera pas

Cela peut être à l'origine de fragments non attribués.

Documentation élastique - Processus de mise à niveau en continu

Marc Tamsky
la source
0

J'ai rencontré exactement le même problème. Cela peut être évité en définissant temporairement l'allocation de partition sur false avant de redémarrer elasticsearch, mais cela ne corrige pas les partitions non attribuées si elles sont déjà là.

Dans mon cas, cela a été causé par le manque d'espace disque disponible sur le nœud de données. Les fragments non attribués étaient toujours sur le nœud de données après le redémarrage, mais ils n'étaient pas reconnus par le maître.

Le simple fait de nettoyer 1 des nœuds du disque a lancé le processus de réplication. C'est un processus assez lent car toutes les données doivent être copiées d'un nœud de données à l'autre.

Brian van Rooijen
la source
0

J'ai essayé de supprimer des fragments non attribués ou de les attribuer manuellement à un nœud de données particulier. Cela ne fonctionnait pas car les fragments non attribués continuaient d'apparaître et l'état de santé était "rouge" encore et encore. Ensuite, j'ai remarqué que l'un des nœuds de données était bloqué dans l'état "redémarrer". Je réduis le nombre de nœuds de données, je l'ai tué. Le problème n'est plus reproductible.

thepolina
la source
0

J'avais deux index avec des fragments non attribués qui ne semblaient pas s'auto-réparer. J'ai finalement résolu ce problème en ajoutant temporairement un nœud de données supplémentaire [1] . Une fois que les indices sont devenus sains et que tout s'est stabilisé au vert, j'ai supprimé le nœud supplémentaire et le système a pu se rééquilibrer (à nouveau) et se remettre dans un état sain.

C'est une bonne idée d'éviter de tuer plusieurs nœuds de données à la fois (c'est ainsi que je suis entré dans cet état). Probablement, je n'avais pas réussi à conserver les copies / répliques pour au moins un des fragments. Heureusement, Kubernetes a gardé le stockage sur disque et l'a réutilisé lorsque j'ai relancé le nœud de données.


... Un certain temps s'est écoulé ...

Eh bien, cette fois, l'ajout d'un nœud ne semblait pas fonctionner (après avoir attendu plusieurs minutes que quelque chose se produise), j'ai donc commencé à fouiller dans l'API REST.

GET /_cluster/allocation/explain

Cela a montré mon nouveau nœud avec "decision": "YES".

À propos, tous les nœuds préexistants étaient "decision": "NO"dus à "the node is above the low watermark cluster setting". C'était donc probablement un cas différent de celui que j'avais abordé précédemment.

Ensuite, j'ai fait le simple POST [2] suivant sans corps , ce qui a mis les choses en marche ...

POST /_cluster/reroute

Autres notes:


[1] Assez facile à faire dans Kubernetes si vous avez assez de marge: il suffit de redimensionner l'ensemble avec état via le tableau de bord.

[2] En utilisant l'interface "Dev Tools" de Kibana, je n'ai pas eu à me soucier des shells SSH / exec.

Brent Bradburn
la source
0

J'ai d'abord augmenté le

"index.number_of_replicas"

de 1 (attendez que les nœuds soient synchronisés) puis diminuez-le de 1 par la suite, ce qui supprime efficacement les fragments non attribués et le cluster est à nouveau vert sans risque de perdre des données.

Je pense qu'il existe de meilleures façons, mais c'est plus facile pour moi.

J'espère que cela t'aides.

Yusuf Demirag
la source
0

Lorsque vous traitez des fragments corrompus, vous pouvez définir le facteur de réplication sur 0, puis le remettre à la valeur d'origine. Cela devrait effacer la plupart sinon tous vos fragments corrompus et déplacer les nouveaux réplicas dans le cluster.

Définition des index avec des réplicas non attribués pour utiliser un facteur de réplication de 0:

curl -XGET http://localhost:9200/_cat/shards |\
  grep UNASSIGNED | grep ' r ' |\
  awk '{print $1}' |\
  xargs -I {} curl -XPUT http://localhost:9200/{}/_settings -H "Content-Type: application/json" \
  -d '{ "index":{ "number_of_replicas": 0}}'

Les remettre à 1:

curl -XGET http://localhost:9200/_cat/shards |\
  awk '{print $1}' |\
  xargs -I {} curl -XPUT http://localhost:9200/{}/_settings -H "Content-Type: application/json" \
  -d '{ "index":{ "number_of_replicas": 1}}'

Remarque: ne l'exécutez pas si vous avez des facteurs de réplication différents pour différents index. Cela coderait en dur le facteur de réplication pour tous les index sur 1.

bonzofénix
la source