一则关于在Elasticsearch中出现”No space left on device”错误导致UNASSIGNED分片的解决方法的故事

这篇文章是“Elastic Stack(Elasticsearch)第2节日日历2019”的第20天的文章。

想要使用保存在Elasticsearch中的数据进行分析时…,我却发现自己被Elasticsearch的烦琐问题所困扰,@ysd_marrrr。

我正在维护一个现在看来设计不好的Elasticsearch服务器,其中的path.data包括了系统分区,在数据积累的过程中导致了系统分区的压力。现在我收到了关于系统分区空间不足的警报,并需要进行确认。

解决了关于分区空间的问题(前提条件),检查Elasticsearch的索引发现状态为RED。
由于集群存在,当其中一个节点宕机时,状态会变为RED,所以在尝试启动宕机节点时,发现集群内所有节点都是存活的?

看到红色指标的分片时,发现部分分片状态为“未分配”…?

$ curl "http://localhost:9200/_cat/shards/myindex1"
myindex1 1  p STARTED 4822406 33.5gb 10.127.110.1 elasticsearch-node1
myindex1 2  p STARTED 4818526 34.6gb 10.127.110.1 elasticsearch-node1
myindex1 3  p UNASSIGNED 4799590 33.3gb 10.127.110.2  elasticsearch-node2
myindex1 4  p STARTED 4824062 33.7gb 10.127.110.3  elasticsearch-node3
myindex1 5  p UNASSIGNED 4804203   34gb 10.127.110.2  elasticsearch-node2
myindex1 6  p STARTED 4824062 33.7gb 10.127.110.3  elasticsearch-node3

在分区空间不足导致分片脱离并进入RED状态的情况下,我用一个简单方法来解决问题而不删除数据,现在与大家分享。

环境:

我正在以下环境中确认。
* 由于涉及 Elasticsearch 5.x 系列,所以请自行获知在 6.x 及更高版本中使用 curl 发送 JSON 的约定。

$ curl "http://localhost:9200/"
{
  "version" : {
    "number" : "5.6.8",
    "lucene_version" : "6.6.1"
  },
  "tagline" : "You Know, for Search"
}

⚠ 我沒有設置複製,但考慮到「資料遺失會帶來相當大的損失」的情況。
⚠ 我認為這不適用於絕對不能刪除數據的生產環境。
⚠ 請在進行此操作之前先確保有足夠的儲存空間。

当使用”Elasticsearch UNASSIGNED” 进行搜索时,有一种方法显得更为突出,即牺牲分片。

当调查解决了”解决未分配问题”的案例时,突出的解决方法是”因为在可以安全删除的分片上发生了问题,因此我们将删除它并分配一个空的分片”。
虽然我们可以谈论复制品或备份,但删除分片可能会带来一些不便,因此我们在寻找其他方法。

在Elasticsearch 5版本中,如何通过强制修复未指派的分片状态(status red)来修复问题。

弹性搜索发生未分配的分片分配-笔记本

在_cluster/allocation/explain中确认 → 实际上有一个解决方案!!

当出现UNASSIGNED时,我首先使用此API来检查分片的分配情况。
然后,确实显示了 No space left on device。

$ curl "http://localhost:9200/_cluster/allocation/explain?pretty"
{
  "index" : "myindex1",
  "shard" : 6,
  "primary" : true,
  "current_state" : "unassigned",
  "unassigned_info" : {
    "reason" : "ALLOCATION_FAILED",
    "at" : "2019-12-01T19:50:00.027Z",
    "failed_allocation_attempts" : 5,
    "details" : "failed to create shard, failure IOException[No space left on device]",
    "last_allocation_status" : "no"
  },
  "can_allocate" : "no",
  "allocate_explanation" : "cannot allocate because allocation is not permitted to any of the nodes that hold an in-sync shard copy",
  "node_allocation_decisions" : [
    {
      "node_id" : "-CLqY8ecTdSkufWq0ba28w",
      "node_name" : "elasticsearch-node3",
      "transport_address" : "10.127.100.3:9300",
      "node_decision" : "no",
      "store" : {
        "in_sync" : true,
        "allocation_id" : "pMm2kOjhRHqJwGba2A7U3Q"
      },
      "deciders" : [
        {
          "decider" : "max_retry",
          "decision" : "NO",
          "explanation" : "shard has exceeded the maximum number of retries [5] on failed allocation attempts - manually call [/_cluster/reroute?retry_failed=true] to retry, [unassigned_info[[reason=ALLOCATION_FAILED], at[2019-12-01T19:50:00.027Z], failed_attempts[5], delayed=false, details[failed to create shard, failure IOException[No space left on device]], allocation_status[deciders_no]]]"
        }
      ]
    },
    {
      "node_id" : "7fhGQ7jQTTS0zTh5YI-GAg",
      "node_name" : "elasticsearch-node1",
      "transport_address" : "10.127.100.1:9300",
      "node_decision" : "no",
      "store" : {
        "found" : false
      }
    },
    {
      "node_id" : "s5J-96kgRraq1E56jHTv2Q",
      "node_name" : "elasticsearch-node2",
      "transport_address" : "10.127.100.2:9300",
      "node_decision" : "no",
      "store" : {
        "found" : false
      }
    }
  ]
}

然而,事实上,这个结果中随便写了一个解决方案。

“解释”:在失败的分配尝试上,分片超过了最大重试次数[5] – 手动调用[/_cluster/reroute?retry_failed=true] 进行重试, [未分配信息[[原因=分配失败],于[2019-12-01T19:50:00.027Z],失败尝试次数[5],延迟=false,详细信息[无法创建分片,失败 IOException[设备上没有剩余空间]],分配状态[决策者无]]]。

发出POST请求到指定的API。

$ curl -XPOST 'http://localhost:9200/_cluster/reroute?retry_failed=true&pretty'

顺利解决了✌

$ curl "http://localhost:9200/_cat/shards/myindex1"
myindex1 1  p STARTED 4822406 33.5gb 10.127.110.1 elasticsearch-node1
myindex1 2  p STARTED 4818526 34.6gb 10.127.110.1 elasticsearch-node1
myindex1 3  p STARTED 4799590 33.3gb 10.127.110.2  elasticsearch-node2
myindex1 4  p STARTED 4824062 33.7gb 10.127.110.3  elasticsearch-node3
myindex1 5  p STARTED 4804203   34gb 10.127.110.2  elasticsearch-node2
myindex1 6  p STARTED 4824062 33.7gb 10.127.110.3  elasticsearch-node3

我無法解決這次未分配的狀態。

我只能删除未分配的分片吗……我努力寻找其他解决方法,但没有找到答案。

/_cluster/reroute 的allocate操作无效。

在一些情况下,如果分片的分配处理不当,可能会导致其状态变为”UNASSIGNED”。然而,通过向/_cluster/reroute发送分配命令,可以解决这个问题。

在谷歌计算中出现未分配给的弹性搜索(Elasticsearch)碎片的分配情况 – 笔记本

Elasticsearch – 如何处理未分配的分片 – Stack Overflow
https://stackoverflow.com/questions/23656458/elasticsearch-what-to-do-with-unassigned-shards/23816954#23816954

让我们试试看吧。

$ curl -XPOST 'http://localhost:9200/_cluster/reroute?pretty' -d '{
  "commands": [{
    "allocate": {
      "index": "myindex1",
      "shard": 5,
      "node": "elasticsearch-node3",
      "allow_primary": true
    }
  }]
}'
{
  "error" : {
    "root_cause" : [
      {
        "type" : "unknown_named_object_exception",
        "reason" : "Unknown AllocationCommand [allocate]",
        "line" : 3,
        "col" : 17
      }
    ],
    "type" : "parsing_exception",
    "reason" : "[cluster_reroute] failed to parse field [commands]",
    "line" : 3,
    "col" : 17,
    "caused_by" : {
      "type" : "unknown_named_object_exception",
      "reason" : "Unknown AllocationCommand [allocate]",
      "line" : 3,
      "col" : 17
    }
  },
  "status" : 400
}

分配,这种事情我可不清楚!然后他出来了,我感到很烦恼。?

“index.routing.allocation.disable_allocation”: false 不起作用

「我通过咨询Elasticsearch支持团队解决了这个问题!」 的方法是将 “index.routing.allocation.disable_allocation” 设置为 false。

分片 – ElasticSearch:未分配的分片,如何修复?- Stack Overflow
https://stackoverflow.com/a/20010544

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

同样地,出现了”未知设置”。即使将变量实际改为已分配的索引,结果也相同。

$ curl -XPUT 'http://localhost:9200/_settings?pretty' -d ' {"index.routing.allocation.disable_allocation": false}'
{
  "error" : {
    "root_cause" : [
      {
        "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"
      }
    ],
    "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"
  },
  "status" : 400
}

看到上面的回答,它清楚地写着v0.90.x和之前的版本。我也尝试过 “cluster.routing.allocation.enable” :”all”,但没有效果。

# 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"
    }
}'

关于水印的内容

根据某些情况,如果水印设置过低,可能不会分配碎片,因此我尝试更改了水印设置。
https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html

如果没有足够磁盘空间的节点,主节点可能无法分配分片(它不会将分片分配到已使用磁盘超过85%的节点)。

Reason 5: 磁盘空间不足
https://www.datadoghq.com/ja/blog/elasticsearch-unassigned-shards/

$ curl -XPUT 'http://localhost:9200/_cluster/settings' -d '{
    "transient": {  
          "cluster.routing.allocation.disk.watermark.low": "90%",
          "cluster.routing.allocation.disk.watermark.high": "95%"
    }
}'

更改水印后立即显示了消息,提醒”由于磁盘使用率超过了水印值,已迁移分片”。

[2019-12-02T15:16:49,472][WARN ][o.e.c.r.a.DiskThresholdMonitor] [elasticsearch-node1] 高磁盘水位线[90%]超过了[-CLqY8ecTdSkufWq0ba28w][elasticsearch-node1][/mnt/elasticsearch/data/nodes/0]的可用空间: 8.4gb[8.4%],将会重新定位分片迁移离开此节点
[2019-12-02T15:16:49,472][INFO ][o.e.c.r.a.DiskThresholdMonitor] [elasticsearch-node1] 重新路由分片:[一个或多个节点的高磁盘水位线被超过]

如果出現了”No space left on device”的错误, 这表示由于缺乏分片移动,水印判定未能正确执行,原因可能是某种问题。
虽然这个设置是默认设置(低85%,高90%),但为什么在默认设置下无法正常工作还不清楚?。

并且在此之后,尝试执行 “/_cluster/reroute” 中的 allocate 等操作,但无法改变 UNASSIGNED 的状态。

最后

被_cluster/allocation/explain 助了真是太好了。
如果在无法从备份还原的情况下查找命令,却被告知“Unknown AllocationCommand [allocate]”,那会变得相当麻烦。所以,为了方便地还原,请准备好副本和备份?

根据我的情况,据说我无法提供足够大的备份存储空间???。

广告
将在 10 秒后关闭
bannerAds