Administrator
发布于 2022-03-22 / 4096 阅读
108

Elasticsearch 分片设计原则与容量规划

集群重启后要 40 分钟才能变绿,问题出在分片数

我们用 ES 做商品搜索和日志检索,版本从 7.15 升到 8.0(2022 年 2 月发布,正式用上)。3 月一次故障演练,重启集群后主分片恢复花了 40 分钟才变绿,期间搜索不可用。排查下来,根因是分片数设错了:一个 200 GB 的索引被切成 5 个分片,每个 40 GB,恢复时要逐分片拷贝、建索引,慢得离谱。

借着这次我重新做了一遍容量规划,把分片设计的几个原则定下来,写在这儿给后来的人。

分片数怎么估:先定单分片大小

ES 官方和社区的共识是:单个分片大小控制在 10 GB 到 50 GB 之间,日志类可以稍大,搜索类建议偏小。太大恢复慢、段合并重;太小则分片元数据开销压垮 master。

我们的商品索引总量约 600 GB,按 30 GB/分片算:

目标分片数 ≈ 总数据量 / 单分片目标大小
          = 600 GB / 30 GB
          ≈ 20 个主分片

但分片数还要能被节点数整除,方便均衡。我们有 6 个数据节点,20 不能被 6 整除,调到 24(每节点 4 个主分片)更均衡。最终建索引:

PUT /product_v2
{
  "settings": {
    "number_of_shards": 24,
    "number_of_replicas": 1
  }
}

24 主 × 1 副本 = 48 个分片(含副本)。每个节点摊 8 个。重建后重启恢复时间从 40 分钟降到 6 分钟,主因是单分片从 40 GB 降到 25 GB,并行恢复更快。

副本策略:高可用和性能的权衡

副本数决定读吞吐和容错能力:

副本数读能力容错存储开销
0无加成挂一个节点就丢数据
1读能力约翻倍允许挂 1 个节点
2读能力约 3 倍允许挂 2 个节点

搜索类查询多,我们设副本 1,读吞吐翻倍且能扛一个节点宕机。日志类(只写不怎么读)设副本 0,省一半存储。

副本不是越多越好。我们曾把日志索引副本设成 1,结果 6 个节点存了 3 TB 日志的 2 倍 = 6 TB,磁盘两周就满。改成副本 0 后存储直接腰斩。

磁盘与内存规划:堆外内存是隐形杀手

ES 是吃内存大户,但堆内存不能超过 50% 的物理内存,且绝对不超过 32 GB(超过会踩 JVM 压缩指针的坑,对象反而更占)。我们节点是 64 GB 内存,堆设 31 GB,剩下约 33 GB 给 Lucene 做文件系统缓存(page cache)。

磁盘规划用这个公式粗算:

所需磁盘 ≈ 原始数据 × (1 + 副本数) × 膨胀系数(约 1.1) / 单节点磁盘可用比例

商品索引 600 GB × 2(副本1)× 1.1 ≈ 1.32 TB,6 节点每节点约 220 GB。我们每块盘 1 TB,留 60% 水位线(ES 默认 watermark),够用。

一个真实故障:某节点磁盘到 92%,ES 触发 watermark.flood_stage把该节点上所有索引设为只读,写入全挂。监控里只看到 "index read-only" 报错,排查了半小时才发现是磁盘。后来把水位线告警提前到 75% 就避免了。

冷热分离:用节点角色把成本压下来

我们的日志场景,最近 3 天查得勤,30 天前的几乎不查。把所有数据放 SSD 热节点太贵。ES 8.0 支持用节点角色(node roles)+ 索引分配感知做冷热分层:

# 热节点(高配 SSD)
node.roles: [ data_hot, ingress ]
# 冷节点(大容量 HDD)
node.roles: [ data_cold ]

# 索引创建时指定落在热节点,7 天后通过 ILM 迁移到冷节点
PUT /logs-2022-03
{
  "settings": {
    "index.routing.allocation.require.data": "hot",
    "number_of_shards": 12,
    "number_of_replicas": 0
  }
}

热节点用 6 台 NVMe SSD(贵但快),冷节点用 3 台大容量 HDD(便宜)。通过 ILM(Index Lifecycle Management)策略,索引满 7 天自动 migrate 到冷节点并降副本。存储成本测算:

方案月存储成本近 3 天查询延迟
全 Hot SSD约 ¥8,40012 ms
冷热分层约 ¥3,10013 ms(热数据仍在 SSD)

每月省 63%,近线查询延迟基本没变,因为高频数据还在 SSD。

我们定的分片规划清单

  • 单分片 10–50 GB,搜索类偏 30 GB,日志类可到 50 GB。
  • 主分片数要能被数据节点数整除,保证均衡;一旦建好不能改,扩容只能新建索引 reindex。
  • 堆内存 ≤ 31 GB,留足 page cache 给 Lucene。
  • 副本数:搜索 1、日志 0;按磁盘和容错需求调。
  • 冷热分层用 node.roles + ILM,把老数据迁到 HDD。
  • 磁盘水位线告警提前到 75%,别等 flood_stage 才发现有问题。

先到这

《Elasticsearch 分片设计原则与容量规划》这块我前前后后踩了不止一次。今天先写这些,后面想到新的再补。

参考