ELK|ES管理之又见 UNASSIGNED SHARD

在ES集群管理过程中,分区(shard)出现unassigned是遇到了比较多的情况了.原因很多常见的两个:节点意外重启(NODE_LEFT),磁盘空间不足(No space left on device).而我最近遇到的情况:操之过急或者说重启节点姿势不正确,造成主分区挂掉,日志无法写入,以至于拖慢整个index.比较宝贵的实战经验记录一下
本文相关版本信息
elasticsearch:6.0.0
kibana:6.0.0
以下操作在 kibana 自带的DevTools进行

查看集群状态

一般出现分区未分配的时候,整个集群的状态都会变成RED

GET _cluster/health

{
  "cluster_name": "cluster_name",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 5,
  "number_of_data_nodes": 5,
  "active_primary_shards": 89,
  "active_shards": 109,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100
}

当然现在状态是正常的,如果不正常的话"status"不是"green"

  "status": "green",
  "active_shards_percent_as_number": 100

"active_shards_percent_as_number"不会是100,以下三个指标也会各有数字

  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,

应对异常

查询shard异常

GET _cat/shards?v&s=state&h=index,shard,prirep,state,unassigned.reason
index                         shard prirep state   unassigned.reason
zzzlog-2020.11.05             1     p      STARTED 
zzzlog-2020.11.05             2     p      STARTED 
zzzlog-2020.11.05             3     p      STARTED 
syslog-2020.11.05             2     r      STARTED 
syslog-2020.11.05             1     p      STARTED 
syslog-2020.11.05             3     r      STARTED 

上面只是示例一下,有异常的话,unassigned.reason那列会有相应的显示
当然,也可以查询指定的index

GET _cat/shards?v&s=state&h=index,shard,prirep,state,unassigned.reason&index=syslog*
index             shard prirep state   unassigned.reason
syslog-2020.11.05 1     p      STARTED 
syslog-2020.11.05 3     p      STARTED 
syslog-2020.11.05 2     p      STARTED 

查询具体原因

GET /_cluster/allocation/explain?pretty
{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[sys-es-001][xx.xx.xx.xx:9300][cluster:monitor/allocation/explain]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "unable to find any unassigned shards to explain [ClusterAllocationExplainRequest[useAnyUnassignedShard=true,includeYesDecisions?=false]"
  },
  "status": 400
}

如果是磁盘不足,或者是节点意外重启,经过上面两步基本就可以看出来了.
节点重启的话,一般起来以后,ES集群是自动再同步一次数据,很快未分配的分区就会消失
磁盘不足自然需要手动扩容或添加磁盘,相应的,重启以后也会有很大的概率自动恢复
当然这里有一个失败次数最大五次的概念,达到次数了,再手动触发一下就好了.

POST /_cluster/reroute?retry_failed=true

对了,有时候直接查询集群分配失败原因/_cluster/allocation/explain并查不到任何东西.我们通过_cat/shards已经知道具体哪个index有问题了,这时候可以直接查询指定的索引

GET /_cluster/allocation/explain?pretty
{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true
}

一般的感冒发烧,到这里就结束了,如果是重症再继续往下看喽

疑难杂症

同样的症状可能原因有很多,以下几招是我运维ES集群两年的经验结晶了.

分区重建之修改索引副本数

有时候分区unassigned状态始终恢复不了,可以尝试调整一下分区的副本数,或增加或减少,大概率会管用

PUT syslog-2020.11.03/_settings
{
  "settings": {
    "index.number_of_replicas": "1"
  }
}

number_of_replicas只要与当前不一致即可.什么不知道当前副本数?查之

GET syslog-2020.11.03/_settings?filter_path=**.number_of_replicas

{
  "syslog-2020.11.03": {
    "settings": {
      "index": {
        "number_of_replicas": "3"
      }
    }
  }
}

哦,对,上面这个filter_path也是个好东西,数据量大时绝对好用

分区重建之手动修改分区节点

既然在这个节点上一直失败,咱换个节点好了

POST _cluster/reroute
{
  "commands": [
    {
      "move": {
        "index": "syslog-2020.08.04",
        "shard": 2,
        "from_node": "es2-master",
        "to_node": "es3-master"
      }
    }
  ]
}

当然,这一招的正经用法是ES集群磁盘分布不匀,手动将磁盘使用过度的分区调到空闲节点

分区重建之创建空分区

分区失败也有可能,是因为里面的数据乱了,丢弃一部分,换来集群正常也是值得的

POST _cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "syslog-2020.08.17",
        "shard": 7,
        "node": "es5-data",
        "accept_data_loss":true
      }
    }
  ]
}

两害相较取其轻,放弃分区数据相对整个索引数据要好接受不少

分区重建绝招之放弃数据

既然放弃分区的数据不行,那便放弃这个index之前写入的所有数据,毕竟后面还有不少要写入不是

DELETE syslog-2020.08.17

这一招算是釜底抽薪了,需要接受数据丢失带来的风险

分区重建绝招之放弃节点

这招是头两天的意外发现,因为那天确实日志量大采集不进来,但是又出了几个线上问题,急需查日志,当时的念头就是无论如果,不能放弃数据.因为只有一个index的一个分区有问题,其它日志还在正常写,但是日志量又大,很快把这个节点的磁盘写满了,想着反正es一会儿也得自动均衡磁盘,直接手动标记这个节点下线算了.

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": "xx.xx.xx.xx"
  }
}

意外的,竟然发现不能创建的那个index的分区自动创建了.谢天谢地!
集群正常了,可以再考虑把这个节点加回来

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": null
  }
}

这个问题的表现是state:INITIALIZING,unassigned.reason: ALLOCATION_FAILED,又一个主分区,还是0副本.当时的查询记录还有:

GET /_cluster/allocation/explain?pretty
{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true
}

{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true,
  "current_state": "initializing",
  "unassigned_info": {
    "reason": "ALLOCATION_FAILED",
    "at": "2020-11-04T14:34:03.022Z",
    "failed_allocation_attempts": 5,
    "details": "failed recovery, failure RecoveryFailedException[[syslog-2020.11.04][2]: Recovery failed on {es-005}{zVzh5mpxSam4dGTFkgh3FA}{ZzWZcNLGT_SgS6tTdguBtQ}{xx.xx.xx.xx}{xx.xx.xx.xx:9300}{box_type=hot}]; nested: IndexShardRecoveryException[failed to recover from gateway]; nested: EngineException[failed to recover from translog]; nested: AlreadyClosedException[this IndexWriter is closed]; nested: IOException[No space left on device]; ",
    "last_allocation_status": "no"
  },
  "current_node": {
    "id": "zVzh5mpxSam4dGTFkgh3af",
    "name": "es-005",
    "transport_address": "xx.xx.xx.xx:9300",
    "attributes": {
      "box_type": "hot"
    }
  },
  "explanation": "the shard is in the process of initializing on node [es-005], wait until initialization has completed"
}

后话

最后还是想提一下敬畏之心.
大数据,什么是大数据呢.一天几百G,历史数据十几T.虽然是日志系统,这么大的数据量,任何一个小的操作都要谨慎谨慎再谨慎.因为你的一个小失误,都是大量的数据或移动或消失或产生,影响都是很难承受的.像前面说的增加副本数number_of_shards,直接的结果就是主机CPU飙升,磁盘疯狂读写,内网网卡几百兆带宽以支撑这么大量的数据交换
最后一句送给自己:es集群很优秀,几十亿条数据毫秒级查询,如果你感觉es搜索慢,99.99%的原因是因为你自己不优秀,没发挥出来es的价值

弄了一个微信群欢迎正常学习elk的朋友扫码交流.
elk


相关博文

About rainbird

IOS攻城狮
This entry was posted in ELK and tagged , , , , , , , , . Bookmark the permalink.

发表评论