ES集群如何做到高可用

ES集群的高可用可分为读高可用、写高可用与发生改变(集群状态改变)时高可用。其实这么说不是很准确,因为部分集群状态的改变会影响读和写的高可用。
读高可用指的是多个副本情况下,某个副本出问题时不影响整个系统的读。
写高可用指的是多个副本情况下,某个副本出问题时不影响整个系统的写,通过translog来确保数据不会丢失。
集群状态的改变的高可用包含自动处理节点的加入和离开,自动同步改变的集群状态,当集群发生故障时自动切换主副shard等等来保持集群的高可用。
读和写的高可用这里不再描述,下面将通过三个部分描述集群状态改变时的高可用。

1、集群状态同步

cluster state是全局性信息, 包含了整个群集中所有分片的元信息(规则,位置, 大小等信息), 并保持每个每节的信息同步。集群状态的详细信息可查看博客:https://www.jianshu.com/p/f46074d95daa
cluster state是由ES的master节点维护的(只有主节点能够改变集群状态), 当它收到data节点的状态更新变化后, 就把这些信息依次广播到其他节点。目前我们一个集群的cluster state在60M左右,当集群状态改变的时候,主节点是否会广播整体的cluster state呢?同步集群状态的时候,ES会做些额外的处理:

  • 只有变化的cluster state信息才会被广播
  • 在cluster state传递之前或做些压缩

具体的过程如下所示:
1、主节点处理一个改变的集群状态,并将改变的状态publish给所有的其他节点。
2、其他节点收到主节点publish的message,向主节点确认收到信息(acknowledge。 it),但不将改变同步到本地的集群状态(not applay it)
3、如果主节点在配置的时间(discovery.zen.commit_timeout 默认30s)没有收到指定个数节点(discovery.zen.minimum_master_nodes)的确认信息,那么该改变的状态就会被rejected。
4、如果主节点在指定的时间内收到了指定个数节点的确认信息,则会提交(commit)该状态的改变,并向其他的节点发送该改变。
5、其他的节点收到信息后,则应用该改变到本地的集群状态中,应用后向主节点发送应用成功信息。
6、主节点等待所有节点的发送的应用成功消息,直到超时(discovery.zen.publish_timeout 默认30s)。

2、节点加入与离开

2.1、节点加入

当一个新节点加入的时候,它通过discovery.zen.ping.unicast.hosts配置的节点获取集群状态,然后找到master节点,并向其发送一个join request(discovery.zen.join_timeout)。主节点接收到reqest后,同步集群状态到新节点。

2.2、非主节点节点离开

当一个节点出现3次ping不通的情况时(ping_interval 默认为1s;ping_timeout 默认为30s),主节点会认为该节点已宕机,将该节点踢出集群。

2.3、主节点离开

当主节点发生故障时,集群中的其他节点将会ping当前的master eligible 节点,并从中选出一个新的主节点。
节点可以通过设置node.master为false来阻止自己变为一个主节点。
通过配置discovery.zen.minimum_master_nodes防止集群出现split brain。该配置通过检查集群中master eligible的个数来判断是否选举出一个主节点。其个数最好设置为(number_master eligible/2)+1,防止当主节点出问题时,一个集群分裂为两个集群。
具有最小编号的active master eligible node将会被选举为master节点。其详细选举过程请看博客:https://www.jianshu.com/p/9454ac19921d

3、分片副本同步

详细信息请看:https://www.easyice.cn/archives/243

elasticsearch 使用 Allocation IDs 的概念,这是区分不同分片的唯一标识(UUIDS)。
Allocation IDs存储在 shard 级元信息中,每个 shard 都有自己的Allocation ID,同时集群级元信息中记录了一个被认为是最新shard 的Allocation ID集合,这个集合称为 in-sync allocation IDs。
如果由于网络或者其他原因,主副shard没有同步,那么副本的shard会将被从in-sync allocation IDs踢出。
举个例子:
个小型集群:一个主节点,两个数据节点。为了保持简单的例子,我们创建只有1个主分片和1个副分片的索引,最初,一个数据节点拥有主分片,另一个数据节点拥有副分片。我们使用 cluster state api 来查阅集群状态中的 in-sync 分片信息,并使用 “filter_path” query 参数来过滤出感兴趣的结果:

GET /_cluster/state?filter_path=metadata.indices.my_index.in_sync_allocations.*,routing_table.indices.my_index.*
result:
{
  "metadata": {
    "indices": {
      "my_index": {
        "in_sync_allocations": {
          "0": [
            "HNeGpt5aS3W9it3a7tJusg",
            "wP-Z5fuGSM-HbADjMNpSIQ"
          ]
        }
      }
    }
  },
  "routing_table": {
    "indices": {
      "my_index": {
        "shards": {
          "0": [
            {
              "primary": true,
              "state": "STARTED",
              "allocation_id": { "id": "HNeGpt5aS3W9it3a7tJusg" },
              "node": "CX-rFmoPQF21tgt3MYGSQA",
              ...
            },
            {
              "primary": false,
              "state": "STARTED",
              "allocation_id": { "id": "wP-Z5fuGSM-HbADjMNpSIQ" },
              "node": "AzYoyzzSSwG6v_ypdRXYkw",
              ...
            }
          ]
        }
      }
    }
  }
}

集群状态显示出主分片和副分片都已启动,主分片分配在数据节点 “CX-rFmo” ,副分片分配在数据节点 “AzYoyz”。他们都有唯一的allocation id,同时,也出现在in_sync_allocations集合中。
让我们看看当关闭主分片所在节点时会发生什么。由于这并不改变分片上的数据,所以两个分片副本应该保持同步。在没有主分片的情况下,副分片也应该被提示为主分片,这些都会反映在集群状态中:

{
  "metadata": {
    "indices": {
      "my_index": {
        "in_sync_allocations": {
          "0": [
            "HNeGpt5aS3W9it3a7tJusg",
            "wP-Z5fuGSM-HbADjMNpSIQ"
          ]
        }
      }
    }
  },
  "routing_table": {
    "indices": {
      "my_index": {
        "shards": {
          "0": [
            {
              "primary": true,
              "state": "STARTED",
              "allocation_id": { "id": "wP-Z5fuGSM-HbADjMNpSIQ" },
              "node": "AzYoyzzSSwG6v_ypdRXYkw",
              ...
            },
            {
              "primary": false,
              "state": "UNASSIGNED",
              "node": null,
              "unassigned_info": {
                "details": "node_left[CX-rFmoPQF21tgt3MYGSQA]",
                ...
              }
            }
          ]
        }
      }
    }
  }
}

由于只有一个数据节点,副分片停留在未分配状态。如果我们再次启动第二个节点,副分片将自动分配在这个节点上。为了使这个场景更有趣,我么不启动第二个节点,相反,我们索引一个文档到新提升的主分片中。由于分片副本现在是差异的(diverging),不活跃的哪个分片副本变为陈旧的,因此他的 ID被主节点从 in-sync 集合中删除:

{
  "metadata": {
    "indices": {
      "my_index": {
        "in_sync_allocations": {
          "0": [
            "wP-Z5fuGSM-HbADjMNpSIQ"
          ]
        }
      }
    }
  },
  "routing_table": {
    ... // same as in previous step
  }
}

现在只剩下一个同步的分片副本,让我们看看如果该副本变为不可用,系统如何处理。为此,我们关闭当前唯一的数据节点,然后启动前一个拥有陈旧分片副本的数据节点,之后,cluster health api 显示cluser health 为red,集群状态显示主分片尚未分配:

{
  "metadata": {
    "indices": {
      "my_index": {
        "in_sync_allocations": {
          "0": [
            "wP-Z5fuGSM-HbADjMNpSIQ"
          ]
        }
      }
    }
  },
  "routing_table": {
    "indices": {
      "my_index": {
        "shards": {
          "0": [
            {
              "primary": true,
              "state": "UNASSIGNED",
              "recovery_source": { "type": "EXISTING_STORE" },
              "unassigned_info": {
                "allocation_status": "no_valid_shard_copy",
                "at": "2017-01-26T09:20:24.054Z",
                "details": "node_left[AzYoyzzSSwG6v_ypdRXYkw]"
              },
              ...
            },
            {
              "primary": false,
              "state": "UNASSIGNED",
              "recovery_source": { "type": "PEER" },
              "unassigned_info": {
                "allocation_status": "no_attempt",
                "at": "2017-01-26T09:14:47.689Z",
                "details": "node_left[CX-rFmoPQF21tgt3MYGSQA]"
              },
              ...
            }
          ]
        }
      }
    }
  }
}

让我们再看看cluster allocation explain API ,这是一个调试分配问题的好工具。 运行不带参数的explain命令将提供系统找到的第一个未分配分片的说明:

GET /_cluster/allocation/explain

explain API 告诉我们为什么主分片处于未分配状态,同时还提供了基于每个节点上的更详细的分配信息。在这个例子中,主节点在集群当前可用节点中无法找到同步的(in-sync)分片副本。

 
{
  "index" : "my_index",
  "shard" : 0,
  "primary" : true,
  "current_state" : "unassigned",
  "unassigned_info" : {
    "reason" : "NODE_LEFT",
    "at" : "2017-01-26T09:20:24.054Z",
    "last_allocation_status" : "no_valid_shard_copy"
  },
  "can_allocate" : "no_valid_shard_copy",
  "allocate_explanation" : "cannot allocate because all found copies of the shard are either stale or corrupt",
  "node_allocation_decisions" : [
    {
      "node_id" : "CX-rFmoPQF21tgt3MYGSQA",
      "node_name" : "CX-rFmo",
      "transport_address" : "127.0.0.1:9301",
      "node_decision" : "no",
      "store" : {
        "in_sync" : false,
        "allocation_id" : "HNeGpt5aS3W9it3a7tJusg"
      }
    }
  ]
}

该API还显示在节点“CY-rFmo”上可用的分片副本是陈旧的( store.in_sync = false )。启动拥有in-sync 分片副本的那个节点将使集群重新变为 green。如果那个节点永远都回来了呢?
reroute API 提供了一个子命令 allocate_stale_primary ,用于将一个陈旧的分片分配为主分片。使用此命令意味着丢失给定分片副本中缺少的数据。如果同步分片只是暂时不可用,使用此命令意味着在同步副本中最近更新的数据。应该把它看作是使群集至少运行一些数据的最后一种措施。在所有分片副本都不存在的情况下,还可以强制Elasticsearch使用空分片副本分配主分片,这意味着丢失与该分片相关联的所有先前数据。 不言而喻,allocate_empty_primary 命令只能用于最糟糕的情况,其含义很好理解。

4、其他介绍

4.1、Pending Task

当集群出问题时,我们在cat health时会看到pending task,pending task到底是什么东西?
只有master节点能处理集群元数据层面的改变任务。大多数情况下,master可以处理,但当集群元数据改变的速度超过了master节点处理的速度时,将会导致这些元数据操作的任务被缓存入队列中,即pending tasks。pending task API 将会显示队列中被挂起的所有的集群元数据改变的任务。
当cluster state 太大的时候,一些改变很容易更新其cluster state,更新一次cluster state会消耗很多cpu还有传送到其他节点的网络带宽,会花费较多的时间。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352