关于elasticsearch:腾讯云Elasticsearch集群规划及性能优化实践

28次阅读

共计 8253 个字符,预计需要花费 21 分钟才能阅读完成。

一、引言

随着腾讯云 Elasticsearch 云产品性能越来越丰盛,ES 用户越来越多,云上的集群规模也越来越大。咱们在日常运维工作中也常常会遇到一些因为后期集群布局不到位,导致前期业务增长集群规模大了之后带来的各种各样的集群可用性及稳定性问题。

这里列举下其中比拟典型的几种集群布局问题:

  • 节点规格布局问题:集群数量很大,然而每个节点的配置很低;
  • 索引分片布局问题:索引很小,然而设置了几十个分片,或者索引很大,只设置了两三个分片;
  • 分片数量布局问题:集群中蕴含 10 万 + 的分片。

正所谓磨刀不误砍柴工,只有后期做好充沛的集群评估布局工作,前期能力省去大量的运维工作。且可能长期保障集群的高可用和高稳定性。

本文联合咱们在给腾讯云 ES 集群日常运维工作中遇到的各种集群问题及总结积淀的一些运维教训,来介绍下如何布局好集群容量及索引配置,以及所遵循的一些准则和教训。文章作者:吴容,腾讯云 Elasticsearch 研发工程师。

二、集群规模及索引布局

1. 集群规模评估

(1)评估什么?

集群规模的评估次要评估以下三个方面:

第一,计算资源评估,计算资源的评估次要是评估单节点的 CPU 和内存。

ES 的计算资源个别耗费在写入和查问过程,通过总结大量 ES 集群的运维教训,2C8G 的配置大略能反对 5k doc/s 的写入,32C64G 的配置大略能撑持 5w doc/ s 的写入能力。

第二,存储资源评估,存储资源的评估次要是评估磁盘的类型及容量大小。

例如 ES 集群应用什么类型的磁盘,SSD 或者高性能云盘。以及每块盘的容量大小,是抉择单盘多容量,还是多盘少容量。而对于冷热拆散的集群,则默认应用 SSD 作为热节点,高性能云盘作为温节点。

另外腾讯云 ES 反对单节点挂载多块云硬盘,且通过性能压测,3 块盘相比于 1 块盘,吞吐量大概有 2.8 倍的晋升。因而如果对写入速度及 IO 性能要求较高,可抉择挂载多块 SSD 磁盘。

ES 冷热拆散多盘集群示意图

第三,节点数量评估,节点数量的评估次要是评估集群数据节点的数量。

在等同集群性能的状况下,倡议优先选择高配置少节点的集群。例如 32C64G3 节点的集群相比于 8C16G12 节点的集群,在集群稳定性和扩容的便捷性上都有肯定的劣势。

因为高配置的集群如果遇到性能瓶颈须要扩容,则只须要横向扩容,即向集群中退出更多等同配置的节点即可;而低配置的集群在扩容节点配置时,则须要纵向扩容。

目前云上的纵向扩容形式有两种:

第一种是 滚动重启形式扩容,这对集群稳定性会有肯定的影响。

第二种是 数据迁徙形式扩容,其原理是先向集群中退出等同数量的高配置节点,而后将低配置节点上的数据迁徙到新节点上,最初再将低配置节点剔除集群,所以这种扩容流程工夫会比拟长,且老本较高。

数据迁徙形式纵向扩容示意图

(2)依据什么评估?

集群规模评估次要依据以下三点来评估:

  • 具体的业务场景,如日志剖析、指标监控、搜寻业务;
  • 业务预计的查问及写入 QPS;
  • 索引的数据总量。

(3)集群规模评估准则

这里联合咱们的运维教训,给出集群规模评估的几点参考倡议:

  • 32C64G 单节点配置通常可承载 5W 次 / s 的写入;
  • 写入量和数据量较大时,优先选择 32C64G 的节点配置;
  • 1T 的数据量预计需耗费 2 -4GB 的内存空间;
  • 搜寻场景优先选择大内存节点配置;
  • 存储容量 = 源数据 (1 + 正本数量) 1.45 (1 + 预留空间)≈ 源数据 (1 + 正本数量) * 2.2.

2. 索引配置评估

(1)评估什么?

索引配置的评估次要评估两点:

第一,如何划分索引?

在应用 index 时,倡议做好定期切换索引的打算。对于日志场景来说,写入不大的状况下倡议按天创立索引,而写入较大的状况下,则倡议按小时创立索引。

定期滚动索引的益处次要包含:可能管制单个索引的大小,晋升读写性能;同时可能形式单个索引太大,影响故障复原的工夫;另外也能防止热索引过大,从而影响快照备份复原的工夫。

第二,如何设置索引主分片数?

云上的索引主分片数默认是 5 个,具体的大小则须要业务依据具体的场景及数据量来优化。上面会给出具体的一些准则和教训。

(2)依据什么评估?

索引配置的评估同样也要联合具体的业务场景及索引的数据量来评估,尤其是单日新增的数据量。

(3)索引配置评估准则

索引配置的评估可依据上面几点准则进行评估:

  • 单个分片大小管制在 30-50GB;
  • 集群总分片数量管制在 3w 以内;
  • 1GB 的内存空间反对 20-30 个分片为佳;
  • 一个节点倡议不超过 1000 个分片;
  • 索引分片数量倡议和节点数量保持一致;
  • 集群规模较大时倡议设置专用主节点;
  • 专用主节点配置倡议在 8C16G 以上;
  • 如果是时序数据,倡议联合冷热拆散 +ILM 索引生命周期治理。

特地须要阐明的是集群分片总数的大小管制上,咱们通过一些性能测试发现:当集群的总分片数超过 10w 个当前,创立索引工夫会增长到分钟级。

尤其是对于写入量在百万 qps 以上的集群,如果总分片数在 10W+,且索引是主动创立的,那么就常常会在每次切换新索引时候,呈现写入陡降、集群不可用的状况。

上面这张图是云上一个 100 个节点,总分片数在 11W+ 的集群。每天 8 点切换新索引时,写入间接掉 0,集群不可用工夫在数小时不等。

集群每天 8 点写入性能受到影响

对于这种问题,咱们腾讯云 ES 团队也有一些十分成熟的优化计划。

其中对于每天八点切换新索引时写入陡降的问题,可通过提前创立索引来解决,且倡议应用固定的 index mapping,防止大量的 put-mapping 元数据更新操作。因为对于这种节点数量和总分片数量都很大的集群来说,更新元数据是一个十分耗费性能的操作。

对于总分片数超过 10W 的问题,这种个别在日志剖析场景中较为常见,如果历史数据不是很重要,则可定期删除历史索引即可。

而对于历史数据较为重要,任何数据都不能删除的场景,则可通过冷热拆散架构 + 索引生命周期治理性能,将 7 天之前的数据存储到温节点,且在索引数据从热节点迁徙到温节点时,通过 Shrink 来将主分片个数升高到一个较小的值,并且可将温节点数据通过快照形式备份到腾讯云 COS 中,而后将温节点上索引的正本设置为 0,这样便可进一步升高集群中的总分片数量。

冷热拆散 +ILM+COS 备份集群架构

二、ES 写入性能优化

 

ES 集群的写入性能受到很多因素的影响,上面是一些写入性能方面的优化倡议:

1. 写入数据不指定 doc_id,让 ES 主动生成

索引中每一个 doc 都有一个全局惟一的 doc_id,这个 doc_id 可自定义,也能够让 ES 主动生成。

如果自定义的话,则 ES 在写入过程中会多一步判断的过程,即先 Get 下该 doc_id 是否曾经存在。如果存在的话则执行 Update 操作,不存在则创立新的 doc。

因而如果咱们对索引 doc_id 没有特地要求,则倡议让 ES 主动生成 doc_id,这样可晋升肯定的写入性能。

2. 对于规模较大的集群,倡议提前创立好索引,且应用固定的 Index mapping

这一条优化倡议在下面也提到了,因为创立索引及新加字段都是更新元数据操作,须要 master 节点将新版本的元数据同步到所有节点。

因而在集群规模比拟大,写入 qps 较高的场景下,特地容易呈现 master 更新元数据超时的问题,这可导致 master 节点中有大量的 pending_tasks 工作沉积,从而造成集群不可用,甚至呈现集群无主的状况。

更新集群元数据超时

集群大量 pending_tasks 工作沉积

3. 对于数据实时性要求不高的场景,适当减少 refresh_interval 工夫

ES 默认的 refresh_interval 是 1s,即 doc 写入 1s 后即可被搜寻到。

如果业务对数据实时性要求不高的话,如日志场景,可将索引模版的 refresh_interval 设置成 30s,这可能防止过多的小 segment 文件的生成及段合并的操作。

4. 对于谋求写入效率的场景,能够将正在写入的索引设置为单正本,写入实现后 关上正本

越来越多的内部客户正抉择将自建的 ES 集群迁徙到腾讯云上来,客户通常是应用 logstash 来迁徙数据,因为自建集群中残缺保留了数据,因而这时候能够将云上的正在写入的索引正本设置为 0,这样可最快实现集群迁徙工作。数据迁徙实现后再将正本关上即可。

5. 应用 Bulk 接口批量写入数据,每次 bulk 数据量大小管制在 10M 左右

ES 为了晋升写入性能,提供了 Bulk 批量写入的 API,通常客户端会筹备好一批数据往 ES 中写入,ES 收到 Bulk 申请后则依据 routing 值进行散发,将该批数据组装成若干分子集,而后异步得发送给各分片所在的节点。

这样可能大大降低写入申请时的网络交互和提早。通常咱们倡议一次 Bulk 的数据量管制在 10M 以下,一次 Bulk 的 doc 数在 10000 高低浮动。

ES Bulk 申请示意图

6. 应用自定义 routing 性能,尽量将申请转发到较少的分片

下面咱们提到 ES 提供了 Bulk 接口反对将数据批量写入到索引,尽管协调节点是异步得将数据发送给所有的分片,然而却须要期待所有的分片响应后能力返回给客户端,因而一次 Bulk 的提早则取决于响应最慢的那个分片所在的节点。这就是分布式系统的长尾效应。

因而,咱们能够自定义 routing 值,将一次 Bulk 尽量转发到较少的分片上。

POST _bulk?routing=user_id

自定义 routing

7. 尽量抉择 SSD 磁盘类型,并且可抉择挂载多块云硬盘

云上目前提供多种类型的磁盘可用抉择,其中 1T 的 SSD 云盘吞吐量为 260M/s,高性能云盘为 150M/s。因而应用 SSD 磁盘对于写入性能和 IO 性能都会有肯定的晋升。

另外腾讯云当初也提供了多盘的能力,绝对于单盘节点来说,3 块盘的吞吐量大概有 2.8 倍的晋升。

8. 解冻历史索引,开释更多的内存空间

咱们晓得 ES 的索引有三种状态,别离是 Open 状态、Frozen 状态和 Close 状态。如下图所示:

ES 索引的三种状态

Open 状态的索引因为是通过将倒排索引以 FST 数据结构的形式加载进内存中,因而索引是可能被疾速搜寻的,且搜寻速度也是最快的。

然而须要耗费大量的内存空间,且这部分内存为常驻内存,不会被 GC 的。1T 的索引预计须要耗费 2 -4GB 的 JVM 堆内存空间。

Frozen 状态的索引特点是可被搜寻,然而因为它不占用内存,只是存储在磁盘上,因而解冻索引的搜寻速度是绝对比较慢的。如果咱们集群中的数据量比拟大,历史数据也不能被删除,则能够思考应用上面的 API 将历史索引解冻起来,这样便可开释出较多的内存空间。

POST /index_name/_freeze

对于解冻索引的搜寻,能够在 API 中指定 ignore_throttled=false 参数:

GET /index_name/_search?ignore_throttled=false
{
 "query": {
   "match": {"name": "wurong"}
 }
}

下面介绍了一些较为常见的写入性能优化的倡议和教训,然而更为高效的优化还须要联合具体的业务场景和集群规模。

三、ES 集群惯例运维经验总结

1. 查看集群衰弱状态

ES 集群的衰弱状态分为三种,别离是 Green、Yellow 和 Red。

  • Green(绿色):全副主 & 正本分片调配胜利;
  • Yellow(黄色):至多有一个正本分片未调配胜利;
  • Red(红色):至多有一个主分片未调配胜利。

咱们能够通过上面的 API 来查问集群的衰弱状态及未调配的分片个数:

GET _cluster/health
{
  "cluster_name": "es-xxxxxxx",
  "status": "yellow",
  "timed_out": false,
  "number_of_nodes": 103,
  "number_of_data_nodes": 100,
  "active_primary_shards": 4610,
  "active_shards": 9212,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 8,
  "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": 99.91323210412148
}

其中须要重点关注的几个字段有 status、number_of_nodes、unassigned_shards 和 number_of_pending_tasks。

number_of_pending_tasks 这个字段如果很高的话,通常是因为 master 节点触发的元数据更新操作,局部节点响应超时导致的大量的工作沉积。

咱们能够通过上面的 API 来查看具体有那些 task 须要执行:

GET /_cat/pending_tasks
insertOrder timeInQueue priority source
       1685       855ms HIGH     update-mapping [foo][t]
       1686       843ms HIGH     update-mapping [foo][t]
       1693       753ms HIGH     refresh-mapping [foo][[t]]
       1688       816ms HIGH     update-mapping [foo][t]

其中 priority 字段则示意该 task 的优先级,翻看 ES 的源码能够看到一共有六种优先级:

IMMEDIATE((byte) 0),
URGENT((byte) 1),
HIGH((byte) 2),
NORMAL((byte) 3),
LOW((byte) 4),
LANGUID((byte) 5);

2. 查看分片未调配起因

当集群 Red 时候,咱们能够通过上面的 API 来查看分片未调配的起因:

GET _cluster/allocation/explain

查看分片未调配的起因

其中 index 和 shard 列出了具体哪个索引的哪个分片未调配胜利。reason 字段则列出了哪种起因导致的分片未调配。这里也将所有可能的起因列出来:

INDEX_CREATED:因为创立索引的 API 导致未调配。CLUSTER_RECOVERED:因为齐全集群复原导致未调配。INDEX_REOPENED:因为关上 open 或敞开 close 一个索引导致未调配。DANGLING_INDEX_IMPORTED:因为导入 dangling 索引的后果导致未调配。NEW_INDEX_RESTORED:因为复原到新索引导致未调配。EXISTING_INDEX_RESTORED:因为复原到已敞开的索引导致未调配。REPLICA_ADDED:因为显式增加正本分片导致未调配。ALLOCATION_FAILED:因为分片调配失败导致未调配。NODE_LEFT:因为承载该分片的节点来到集群导致未调配。REINITIALIZED:因为当分片从开始挪动到初始化时导致未调配(例如,应用影子 shadow 正本分片)。REROUTE_CANCELLED:作为显式勾销从新路由命令的后果勾销调配。REALLOCATED_REPLICA:确定更好的正本地位被标定应用,导致现有的正本调配被勾销,呈现未调配。

detail 字段则列出了更为具体的未调配的起因。上面我会总结下在日常运维工作中常见的几种起因。

如果未调配的分片比拟多的话,咱们也能够通过上面的 API 来列出所有未调配的索引和主分片:

GET /_cat/indices?v&health=red

3. 常见分片未调配起因总结

(1)磁盘满了

the node is above the high watermark cluster setting [cluster.routing.allocation.disk.watermark.high=95%], using more disk space than the maximum allowed [95.0%], actual free: [4.055101177689788%]

当咱们执行 _cluster/allocation/explain 命令后看到下面的一行语句的话,则能够判断是该索引主分片所在的节点磁盘满了。

解决办法:扩容磁盘晋升磁盘容量或者删除历史数据开释磁盘空间。

通常如果磁盘满了,ES 为了保障集群的稳定性,会将该节点上所有的索引设置为只读。ES 7.x 版本之后当磁盘空间晋升后可主动解除,然而 7.x 版本之前则须要手动执行上面的 API 来解除只读模式:

PUT index_name/_settings
{
 "index": {
   "blocks": {"read_only_allow_delete": null}
  }
}

(2)分片的文档数超过了 21 亿条限度

failure IllegalArgumentException[number of documents in the index cannot exceed 2147483519

该限度是分片维度而不是索引维度的。因而呈现这种异样,通常是因为咱们的索引分片设置的不是很正当。

解决办法:切换写入到新索引,并批改索引模版,正当设置主分片数。

(3)主分片所在节点掉线

cannot allocate because a previous copy of the primary shard existed but can no longer be found on the nodes in the cluster

这种状况通常是因为某个节点故障或者因为负载较高导致的掉线。

解决办法:找到节点掉线起因并重新启动节点退出集群,期待分片复原。

(4)索引所需属性和节点属性不匹配

node does not match index setting [index.routing.allocation.require] filters [temperature:"warm",_id:"comdNq4ZSd2Y6ycB9Oubsg"]

解决办法:从新设置索引所需的属性,和节点保持一致。因为如果从新设置节点属性,则须要重启节点,代价较高。

例如通过上面的 API 来批改索引所须要调配节点的温度属性:

PUT /index_name/_settings
{
  "index": {
    "routing": {
      "allocation": {
        "require": {"temperature": "warm"}
      }
    }
  }
}

(5)节点长时间掉线后重新加入集群,引入了脏数据

cannot allocate because all found copies of the shard are either stale or corrupt

解决办法:通过 reroute API 来重新分配一个主分片:

POST _cluster/reroute?pretty"-d'{
    "commands" : [
        {
          "allocate_stale_primary" : {
              "index" : "article", 
              "shard" : 1,
              "node" : "98365000222032",
              "accept_data_loss": true
          }
        }
    ]
}

(6)未调配分片太多,达到了分片复原的阈值,其余分片排队期待

reached the limit of incoming shard recoveries [2], cluster setting [cluster.routing.allocation.node_concurrent_incoming_recoveries=2] (can also be set via [cluster.routing.allocation.node_concurrent_recoveries])

这种状况通常呈现在集群重启,或者某一个节点重启后。且因为设置的分片并发复原的值较低导致。为了尽快恢复集群衰弱状态。

解决办法:能够通过调用上面的 API 来晋升分片复原的速度和并发度:

PUT /_cluster/settings
{
    "transient" : {
        "cluster.routing.allocation.node_concurrent_recoveries": "20",
        "indices.recovery.max_bytes_per_sec": "100mb"
    }
}

结语

本文介绍了集群规模和索引配置布局的评估准则,根据这些准则提前布局集群,能够保障集群的稳定性和可用性,简化简单的运维工作。

另外介绍了一些常见的写入性能优化的倡议和办法。可能进一步晋升集群的写入性能和稳定性。最初介绍了日常运维工作中常见的排查集群问题的办法和思路。心愿本文可能帮忙到腾讯云的每一个 ES 客户。

正文完
 0