最佳分片大小:平衡集群性能与管理

掌握Elasticsearch分片大小以优化集群性能。本指南探讨了分片数量与大小之间的权衡,涵盖数据量、索引负载和查询模式等关键因素。了解计算最佳分片分配、利用基于时间的索引以及实施索引生命周期管理(ILM)的最佳实践,以构建可扩展且高效的Elasticsearch集群。

最佳分片大小:平衡集群性能与管理

分片大小是Elasticsearch中看似简单,但在集群运行几个月后就会变得复杂的问题之一。分片本质上是一个Lucene索引,但每个分片都有开销。太多的小分片会使集群忙于管理元数据和微小的搜索目标。太少的大分片会使重新定位、恢复以及某些搜索变得异常缓慢。

没有适用于所有集群的通用分片大小。具有每日滚动更新的日志集群、产品搜索索引和安全分析集群的行为各不相同。实用的方法是选择一个目标分片大小,围绕它设计滚动更新或索引创建,然后根据实际的索引和查询行为进行调整。

Elasticsearch分片基础

在深入探讨大小策略之前,理解基本概念至关重要:

  • 索引:文档的集合。在Elasticsearch中,索引被划分为多个分片。
  • 分片:分布单元。每个分片是一个独立的Lucene索引。一个索引可以包含多个分片,分布在集群的不同节点上。
  • 主分片:创建索引时,会分配一定数量的主分片。这些分片是数据索引的位置。你不能简单地修改现有索引的number_of_shards,但Elasticsearch在特定条件下提供了拆分和收缩操作。许多团队仍将主分片数量视为设计时的决策,因为后续更改需要规划。
  • 副本分片:主分片的副本。它们提供冗余并提高读取吞吐量。如果主分片发生故障,副本可以提升为主分片。副本分片的数量可以随时更改。

分片如何影响性能

  • 索引性能:每个分片都需要资源进行索引。更多的分片意味着管理请求的协调节点有更多开销。然而,如果分片变得太大,索引到单个分片可能成为瓶颈。
  • 查询性能:搜索请求被分发到所有相关的主分片。分片数量越多,需要处理的请求数量可能增加,从而可能增加延迟。相反,非常大的分片可能导致更长的搜索时间,因为Lucene需要在该分片内处理更多数据。
  • 集群管理:大量分片会增加主节点的负载,主节点负责集群状态管理。它还会影响分片重新定位、快照和恢复等操作的开销。
  • 资源利用:每个分片消耗内存和磁盘I/O。过多的分片可能耗尽节点资源,导致性能下降或节点不稳定。

分片大小的关键考虑因素

“理想”的分片大小并非固定数字;它取决于你的特定工作负载、数据特征和硬件。然而,有几个因素应指导你的决策:

1. 数据量和增长率

  • 当前数据大小:你的索引当前有多少数据?
  • 增长率:数据增长的速度有多快?这有助于预测未来的分片大小。
  • 数据保留策略:你会删除旧数据吗?这会影响活跃数据的有效大小。

2. 索引负载

  • 索引速率:你每秒索引多少文档?
  • 文档大小:单个文档的平均大小是多少?
  • 索引吞吐量:你的节点能否以当前分片配置处理索引负载?

3. 查询模式

  • 查询复杂度:你的查询是简单的关键词搜索还是复杂的聚合?
  • 查询频率:查询数据的频率如何?
  • 查询延迟要求:可接受的响应时间是多少?

4. 集群拓扑和资源

  • 节点数量:集群中有多少个节点?
  • 节点硬件:CPU、RAM和磁盘(强烈推荐SSD用于Elasticsearch)。
  • 分片限制:Elasticsearch包含安全限制,防止节点持有过多打开的分片。较新版本通常使用cluster.max_shards_per_node作为正常打开索引的集群级防护。cluster.routing.allocation.total_shards_per_node不同:它限制来自单个索引或匹配分配范围的分片可以分配到一个节点的数量。在更改任一设置之前,请检查你的Elasticsearch版本。

分片分配的最佳实践

1. 设定目标分片大小

虽然没有魔法数字,但许多生产集群的目标分片大小在10GB到50GB之间,适用于常见的日志和搜索工作负载。这个范围是起点,而非规则。高吞吐量或长期保留的系统可能在测试后选择更大的分片;小型企业搜索索引可能最适合使用单个小分片。

  • 太小(< 10GB):可能导致过多开销。每个分片都有内存占用,并增加主节点的负载。管理数千个小分片会成为重大的运营负担。
  • 太大(> 50GB):可能导致性能问题。合并段、恢复和再平衡操作需要更长时间。如果一个大分片发生故障,恢复可能需要相当长的时间。

2. 考虑基于时间的索引

对于时间序列数据(日志、指标、事件),使用基于时间的索引是一种标准且高效的做法。这涉及为特定时间段(例如,每天、每周、每月)创建新索引。

  • 示例:而不是一个巨大的索引,你可能会有logs-2023.10.26logs-2023.10.27等。
  • 好处:更容易的数据管理(通过索引生命周期管理 - ILM删除旧索引),更好的性能(因为查询通常针对近期数据),以及可控的分片大小。

3. 实施索引生命周期管理(ILM)

ILM策略允许你根据年龄、大小或文档计数自动管理索引。你可以为索引定义阶段(热、温、冷、删除),并为每个阶段指定操作,包括更改副本数量、收缩索引或删除它们。

  • 热阶段:索引正在被积极写入和查询。最大化性能。
  • 温阶段:索引不再写入但仍被查询。可以移动到性能较低的硬件,可能减少副本或收缩。
  • 冷阶段:不常查询。根据你的Elasticsearch许可证、版本和架构,数据可以移动到更便宜的存储或性能较低的节点。
  • 删除阶段:数据不再需要并被删除。

4. 避免过度分片

过度分片是指分片数量远超集群大小和数据量。这是一个常见陷阱,会导致性能不佳和管理问题。

  • 症状:主节点CPU使用率高、集群状态更新缓慢、恢复时间长以及整体反应迟钝。
  • 缓解措施:从一开始就规划主分片数量。对于基于时间的索引,从每个索引合理数量的主分片开始(例如,1或3)。你以后总是可以添加副本。

5. 不要过度索引

同样,避免在不需要时创建过多的索引。每个索引都会增加开销。对于没有自然分区机制的非时间序列数据,考虑单个索引配合适当的分片数量是否足够。

6. 考虑number_of_shards设置

创建索引时,number_of_shards参数定义主分片的数量。此设置在索引创建后不可更改。

PUT my-index
{
  "settings": {
    "index": {
      "number_of_shards": 3,  // 示例:3个主分片
      "number_of_replicas": 1   // 示例:1个副本分片
    }
  }
}
  • 提示:对于较小的索引或索引/查询负载非常低的索引,单个主分片可能就足够了。对于更大、更活跃的索引,3或5个主分片可以提供更好的分布和弹性,特别是如果你计划稍后拆分索引(尽管拆分很复杂)。

7. 再平衡和重新定位

Elasticsearch会自动再平衡分片以确保在节点间均匀分布。然而,如果分片太大,这些操作可能消耗大量资源且速度缓慢。较小、数量更多的分片有时可以更快地再平衡,但这被管理更多分片的开销所抵消。

8. 查询性能调优

如果查询性能不佳,评估你的分片策略。考虑:

  • 分片数量:太多分片可能增加协调开销。
  • 分片大小:非常大的分片可能减慢段合并和分片内搜索。
  • 索引设计:你是否使用了适当的映射和分析器?

计算最佳分片数量

没有单一的公式,但这里有一个常见的方法:

  1. 估计索引在其生命周期内的总数据量。
  2. 确定目标分片大小(例如,30GB)。
  3. 计算所需的主分片数量总数据量 / 目标分片大小
  4. 向上取整到最接近的整数。这给出了索引的number_of_shards
    • 示例:如果你预计90GB数据,目标分片大小为30GB,你需要90GB / 30GB = 3个主分片。
  5. 考虑弹性和分布:对于关键索引,考虑使用3或5个主分片,以允许更好的分布和恢复选项,即使初始数据量并不严格要求。权衡是增加的开销。
  6. 从保守开始:通常添加副本比更改主分片数量更容易(后者通常需要重新索引或复杂的变通方法)。如果不确定,从较少的主分片开始,并监控性能。

示例场景:日志分析

假设你正在索引应用程序日志:

  • 数据量:你预计每月1TB日志。

  • 数据保留:你保留日志30天。

  • 目标分片大小:你设定为20GB。

  • 每日索引:你创建每日索引(logstash-YYYY.MM.DD)。每个每日索引将包含大约1TB / 30天 ≈ 33GB的数据。

  • 每个索引的主分片:鉴于20GB的目标和33GB的每日数据量,你可能选择每个索引2个主分片(33GB / 20GB ≈ 1.65,向上取整为2)。这确保单个分片保持在目标大小内。

  • 副本:你决定使用1个副本以实现高可用性。

  • 总分片:在30天的保留期内,你将有30个索引,每个索引有2个主分片和2个副本分片,总计任何时候都有60个主分片和60个副本分片活跃。

这种方法使单个分片保持可管理,并允许通过简单地删除旧索引来高效删除数据。

常见问题

最常见的问题是由于习惯导致的过度分片。有人创建每日索引,使用五个主分片和一个副本,因为一个旧教程使用了这个设置。起初看起来无害。然后集群有数百个小索引、数千个小分片,主节点花费太多时间在集群状态更新上。搜索也会分散到许多分片,在实际查询工作开始之前就增加了协调开销。

相反的问题出现在恢复期间。几个巨大的分片在正常日子可能查询良好,但当节点故障或滚动重启开始时,重新定位需要很长时间。快照和恢复也可能变慢,因为每个分片是一个大的工作单元。如果你的恢复目标很紧,即使查询延迟看起来不错,分片大小也很重要。

热分片是另一个实际问题。如果所有新写入都进入一个主分片,添加更多节点不会自动分散写入负载。基于时间的滚动更新有帮助,因为新索引可以根据当前流量模式调整大小。路由选择也很重要。自定义路由可能很强大,但糟糕的路由键可能将太多数据发送到一个分片。

更好的滚动更新模式

对于时间序列数据,基于大小的滚动更新通常比固定的每日索引更容易管理。而不是无论数据量如何每天创建一个索引,你创建一个写入别名,让ILM在索引达到目标大小、年龄或文档计数时滚动更新。

PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_primary_shard_size": "30gb",
            "max_age": "1d"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

使用这种模式,一个安静的周末可能产生更少的索引,而一个繁忙的事件日可以更早地滚动更新。你仍然需要选择初始的主分片数量,但滚动更新可以防止分片增长偏离目标太远。

如何检查当前分片

在更改任何内容之前,查看你当前的集群:

GET _cat/shards?v&h=index,shard,prirep,state,docs,store,node&s=store:desc
GET _cat/indices?v&h=index,pri,rep,docs.count,store.size,pri.store.size&s=pri.store.size:desc
GET _cluster/health

你要寻找模式:许多小分片、几个巨大分片、未分配的分片、不均匀的节点放置,或者主存储大小远离你预期目标的索引。如果一个索引有100GB主数据和五个主分片,每个主分片在副本之前大约20GB。如果同一个索引有100GB和50个主分片,你可能创造了不必要的开销。

最后说明

良好的分片大小设置与其说是追求完美数字,不如说是保持集群易于操作。从一个合理的目标开始,在数据模式合适的地方使用ILM或滚动更新,并观察分片大小、查询扇出、恢复时间和节点压力的实际情况。如果你的集群已经过度分片,逐步修复它,使用新的索引模板、滚动更新、收缩或重新索引,而不是试图一次性将所有旧索引强制转换为新形状。