乔叔教 Elastic - 30 - Elasticsearch 的优化技巧 (4/4) - Shard 的最佳化管理

Elasticsearch 的优化技巧 系列文章索引


前言

这系列的文章主要的目的在於当我们开始使用 Elastic Stack 时,我们如何优化 Elasticsearch 的使用方式,包含 Indexing, Searching, Disk Usage, Shard Optimization 等四个主题,这篇以是 Shard Optimization 为主的介绍。

进入此章节的先备知识

  • 已经有在使用 Elasticsearch,并且了解 Elasticsearch 的基本原理与操作方式。

此章节的重点学习

  • 如何规划属於你的 Sharding Strategy 来管理 Elasticsearch Cluster 中的 Shards。
  • 当 Elasticsearch Cluster 已经 oversharding 了,要如何修正。

Shard 的最佳化管理方式 - Sharding Strategy

为了避免机器毁损时造成资料的遗失以及提升 indexing 或是 searching 的资料处理能力,Elasticsearch Cluster 在多个 nodes 并包含多个 shards 的分散式资料架构中,储存 index 资料和这些资料的 replica,但是这些 shards 的数量,以及 replica 的数量,对於 cluster 的健康状态及效能其实有很大的影响,最常遇到的一个问题就是 oversharding (过多的分片),而这种 shard 数量太多的状况可能会影响到 cluster 的稳定性,因此在管理 Elasticsearch Cluster 时,最好先了解你的资料,并规划好 Sharding Strategy ,以下是规划时建议要考量的项目。

  • Search 在执行时,一个 Shard 会分配一个 Thread,数量太多反而会拖慢速度
  • 每个 Shard 都有基本运作的成本,数量太多成本愈高
  • 指定 Shard 在 Cluster 中的分配方式,以优化储存硬体的资源
  • 删除整批资料时,以 Index 为单位来删除,而不要从一批 Documents 来删除
  • 建议使用 Data Stream 或 Index Lifecycle Management (ILM) 来管理 time series 资料
  • 一般会建议让单一 Shard 的大小在 10 ~ 50 GB 左右
  • 1GB 的 Heap Memory 大约能处理 20 个 Shards
  • 一个 Index 有多个 Shard 时,避免大多数的 Shard 都被分配在同一台 Node 身上

底下分别是这些建议的个别说明。

Search 在执行时,一个 Shard 会分配一个 Thread,数量太多反而会拖慢速度

大多数的 searching 在执行时,查询的资料是会横跨多个 shards,而每个 shard 在搜寻时会使用一个 CPU thread 在处理执行,也就是:

  • 如果有多个 shard,可以让查询的处理并发在多个 shard 身上同时进行,以增加处理的效率。
  • shard 数量愈多,node thread pool 的消耗也愈多,因此 thread pool 数量不足的话,反而会影响查询的执行效率。

一个 Node 依照不同的功能分类有多种 Thread pool, 其中 search (count/search/suggest) 的 size 是 int((# of allocated processors * 3) / 2) + 1 并且 queue_size 预设是 1000 ,而 write (index/delete/update/bulk) 的 size 是 # of allocated processors ,预设的 queue_size 也是 1000。( 官方文件 - Thread pools )

每个 Shard 都有基本运作的成本,数量太多成本愈高

每个 Shard 固定都会占用一些 CPU 和 Memory 的资源,以同样的资料量,Shard 数量愈多,overhead 也就愈高,占用的总系统资源也会较多一些。

Shard 的另外的资源成本有一部份会是里面的 sgement files,segment files 的 metadata 会被存放在 JVM heap memory 中,以提供搜寻时处理的加速,而 segment files 在经过 merge 後,也会将已标示为删除的资料给移除,加上 segment files 数量变少,占用的 heap memeory 也会较少。

指定 Shard 在 Cluster 中的分配方式,以优化储存硬体的资源

预设是自动分配,而 Elasticsearch 也就会尽可能的平均分配,而我们可以使用 shard allocation awareness 的机制来自己决定 shard 被分配的规则,并依照业务的需求来分配不同等级的硬体给不同的资料。

如果是 time-based 的资料,也可以把时间较旧、使用率较低的资料,分配到较次等的硬体上,以优化储存硬体的成本,这部份也可以参考 Hot-Warm-Cold architecture 的运作机制来处理。

删除整批资料时,以 Index 为单位来删除,而不要从一批 Documents 来删除

Document 的删除,在 Elasticsearch 的运作上,是产生另外一笔 "标示删除" 的记录在 segment files 中,所以这些都还是会持续的占用系统资源,一直到 segment merge 之後,才会真正的被移除。

因此如果会周期性的删除一批旧资料时,最好能以 Index 为单位来删除,而不是透过 delete_by_query 之类的批次删除机制。

建议使用 Data Stream 或 Index Lifecycle Management (ILM) 来管理 time series 资料

Index Lifecycle Management 里面可以定义 自动 Rollover 的机制,也就是当资料量成长到 某个数量某个时间某个大小 时,会自动产生新的 Index 来放新的资料,而太旧的资料也能设定自动删除。

使用 ILM 是个很好来管理 Shard Strategy 的工具,因为他能很轻易的进行策略的调整:

  • 因为 ILM 都会透过 Index Template 来管理 Indices,所以要改变 primary shard 数量时,直接改 index template 即可。
  • 想要 shard 总数成长慢一点、单一 shard 的大小要大一点时,只要修改 Rollover 的配置规则。
  • 当 shard 数量太多、旧资料要删掉时,只要修改 delete phase 的规则。

一般会建议让单一 Shard 的大小在 10 ~ 50 GB 左右

Shard 太大时,会让 Cluster 进行 shard recover 时的成本太高。例如一个 node 死掉时,Cluster 会尝试进行 rebalance ,这时要将某个 node 身上的 shard 搬到另一个 node 时,这个搬家所消耗的频宽与处理的系统资源都会是成本。

不过这个还是要依照 Cluster 的硬体规格及 Node 的数量来进行全面的评估。

1GB 的 Heap Memory 大约能处理 20 个 Shards

一个 node 能处理的 shard 数量大约会和 JVM heap memory 大小成一定的比例,以官方统计的数字,一般是每 GB 的 heap memory 大约可以处理 20 个 shards,也就是 30GB 的 heap memory 可以处理 600 个 shards,不过这同样的还是要依照 Elasticsearch Cluster 的硬体规格与使用状况来评估。

若要查看 shard 数量,可以从 _cat API 来看

GET _cat/shards

一个 Index 有多个 Shard 时,避免大多数的 Shard 都被分配在同一台 Node 身上

当我们将一个 Index 设定有多个 primary shard 时,主要的目的就是为了 indexing 时能有更多的 Nodes 能分担处理,但一个 Cluster 可能有许多的 Index ,在各种混合分配的情况下,若是 shard allocation 的机制刚好把这个 Index 把 shard 分到同一个 Node 身上的话,这样就达不到我们要的目的。

因此可以透过 index.routing.allocation.total_shards_per_node 的设定,来限制每个 node 可以被分配存放这个 index 多少个 shard,设定方式如下:

PUT /my-index-000001/_settings
{
  "index" : {
    "routing.allocation.total_shards_per_node" : 5
  }
}

修正 oversharging (过多的 shards) Cluster 的方法

当 Cluster 已经因为太多的 shards 导致不太稳定时,我们可以透过以下的方式来进行调整或修正。

  • 使用较长时间区间的 time-based indices 配置方式
  • 删掉空的或没必要的 Indices
  • 在系统较不忙的时段,执行 Force Merge 来合并 Segment Files
  • 透过 Shrink API 将现有的 Index 的 shard 数量变少
  • 透过 reindex API 来合并较小的 indices

底下分别是这些建议的个别说明。

使用较长时间区间的 time-based indices 配置方式

针对 time-based 资料,我们可以提高切 Index 的时间颗粒度,例如本来是 1天 切一个 Index,我们可以改成 1个月、或 1年 来切 Index。

如果是使用 Index Lifecycle Management 来处理 time-based indices 时,就可以透过提高 max_age, max_docs, max_size 的这些配置来达到同样的目的。

删掉空的或没必要的 Indices

如果是使用 ILM 的 max_age 机制来进行 Index 的 rollover 时,有可能会产生出空的 index,这些空的 indices 也会占用到一些系统资源,这样的 Index 应该查询出来并且删除。

在系统较不忙的时段,执行 Force Merge 来合并 Segment Files

透过 Segment Files 的 merge 来减少占用的系统资源与空间,将资源能提供给其他的任务。

也因为 forcemerge 的执行时很占用系统资源,所以建议要在系统较不忙的时候来做这个动作。

POST /my-index-000001/_forcemerge

透过 Shrink API 将现有的 Index 的 shard 数量变少

如果 Index 已经不再会写入新的资料时,可以透过 Shink API 来将 primary shard 的数量减少。详细的设定方式可以参考先前的文章,或是 官方文件 - Shrink index API

若是使用 ILM 的话,也可以在 warm phase 时设置 Shrink 的处理。

透过 reindex API 来合并较小的 indices

例如原先我们是以 来当作 time-based indices 的切割单位,若是 index 数量太多,因此造成 shard 数量太多,我们可以透过 reindex 的方式这些 indices 的资料合并到以 为单位的 index。

POST /_reindex
{
  "source": {
    "index": "my-index-2099.10.*"
  },
  "dest": {
    "index": "my-index-2099.10"
  }
}

这样也会是一种减少 shard 数量的方式。

参考资料


查看最新 Elasticsearch 或是 Elastic Stack 教育训练资讯: https://training.onedoggo.com
欢迎追踪我的 FB 粉丝页: 乔叔 - Elastic Stack 技术交流
不论是技术分享的文章、公开线上分享、或是实体课程资讯,都会在粉丝页通知大家哦!

此系列文章已整理成书
乔叔带你上手 Elastic Stack:Elasticsearch 的最佳实践与最佳化技巧
书中包含许多的修正、补充,也依照 Elastic 新版本的异动做出不少修改。
有兴趣的读者欢迎支持! 天珑书局连结
乔叔带你上手 Elastic Stack:Elasticsearch 的最佳实践与最佳化技巧


<<:  完美 camp 进化论

>>:  Day30 末日总结

iOS APP 开发 OC 第九天,网路请求原理

tags: OC 30 day 因为工作的需求,今天跳级来写写网路请求。 NSURLConnecti...

企业资料通讯Week6 (1) | DNS(网域名称系统)[二]

DNS Message DNS 的讯息传递也是两种:Query 与 Reply(就是要求与回覆),它...

Day 1. 前言

在决定铁人赛的题目前,我刚好有个前同事传讯息问我近况,顺便想套一下我当时的薪水,当时在公司大家对於薪...

Day 2 - Using Google reCAPTCHA with ASP.NET Web Forms C#「我不是机器人」验证

=x= 🌵 CONTACT Page 寄信页的「我不是机器人」验证功能,後端实作。 Google r...

Day 19 资料宝石:RDS是什麽?RDS vs EC2 (+db) 方案比较

今天开箱第四颗宝石,我们将比较 RDS 与 EC2 方案的不同处,用来切入为何 AWS RDS 成...