Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

ElasticSearch 分片

ES 的性能、稳定性、扩展性,90% 取决于分片规划。

1. 什么是分片(Shard)

ElasticSearch 一个索引由多个分片组成:

类型 功能
Primary Shard(主分片) 实际写入数据
Replica Shard(副本) 容灾 + 提高查询性能

每个分片本质上是一个 Lucene Index(底层最小单元)。

ES 只做 “分布式调度”,真实存储由 Lucene 完成。

2. 为什么分片非常关键?

错误的分片数量会导致:

  • 性能崩溃(太多 shard -> JVM 内存暴涨)
  • 查询变慢(Broadcast 查询)
  • 集群重启慢、恢复慢
  • 数据迁移慢
  • 写入吞吐下降
  • 集群频繁不稳定(yellow、red)

分片反模式是 ES 最常见的集群故障源头。

3. 分片数量如何决定?

核心公式:

每个 Shard 的理想大小:30 ~ 50GB

原因:

  • 分片太小:浪费内存、CPU、filehandle
  • 分片太大:迁移慢、恢复慢、merge 巨慢

分片数量计算公式

假设一个索引未来 1 年最多:

  • 数据:2 TB
  • 采用每 shard 40GB
2000GB / 40GB = 50 个 shard

如果集群有 3 个 data 节点:

每节点 ≈ 16–17 个 shard(正常)

4. 正确选择分片数量(简洁版)

数据量(索引) 推荐 primary shard
< 50GB 1 shard(最佳)
50–200GB 2–4 shards
200–500GB 4–10 shards
>500GB 10+ shards(按 40GB/shard 或 ILM 滚动)

5. 分片数量的真实影响

5.1 查询性能

例如你有 10 shard,一个查询会广播到所有 shard:

  • 10 个 shard -> OK
  • 2000 个 shard -> GG(爆炸式变慢)

5.2 内存占用(JVM heap)

每 shard 都需要:

  • 文件句柄(file handle)
  • JVM segment metadata
  • Lucene 索引结构

结论:

Shard 不是越多越好,越少越强。

5.3 写入吞吐

更多 shard = 更多 Lucene 索引 -> 慢。

5.4 Merge 开销

Lucene 写入时会不断产生小 segment,后续自动 merge。

Shard 越多 -> merge 越多 -> IO 延迟暴增。

6. Replica(副本)规划

副本 = 高可用 + 查询读负载能力

建议:

场景 副本
写入密集(日志) 0(写入高峰时),正常时 1
普通业务 1
高读取量(搜索类) 2–3

7. 分片分配与节点规划

7.1 每台机器的 shard 数量控制

经验值:

每节点 shard 数 ≤ 20 × CPU核心数

例如:

  • 8 核节点:最多 ≈ 160 shards
  • 16 核节点:最多 ≈ 320 shards

超过这个通常会抖动甚至频繁 GC。

7.2 Hot/Warm 架构(推荐)

适合日志系统、ES 官方推荐:

  • Hot Node:SSD,存放最近 7 天
  • Warm Node:普通 SSD,大量数据
  • Cold Node:低成本存储

8. shard resizing(动态调整分片)

ES 支持:

8.1 shrink(缩小 shard 数)

条件:

  • 只能从多个 shard -> 1 shard
  • 索引必须是只读

示例:

POST logs-2025-01/_shrink/logs-2025-01-single

8.2 split(增加 shards)

条件:

  • 原 shard 数量必须是扩大后的整除关系

例如 2 -> 4 -> 8 可以,但 3 -> 5 不行。

9. 滚动索引(RollOver)是最好的分片管理方法

适用于日志、订单、行为数据:

使用 ILM:

当 index.size > 40GB -> 自动 rollover

优点:

  • 不必一次性规划无限大的分片数
  • 每天/每周一个索引,天然分片
  • 数据可按生命周期自动删除(delete phase)

10. 常见的分片反模式(必须避免)

❌ 反模式 危害
给每个用户建一个 index field explosion + shard explosion
给每个用户建一个 shard 直接爆炸
1TB 数据用 1 shard 迁移灾难
一个索引 2000 shards 查询、内存全部崩溃
频繁 split、shrink shard 会导致中断和性能下降
log/behavior 不按日期切分 巨无霸 shard
ES 当 OLTP 用 大量写入 + 分片频繁更新灾难

11. 如何为你的业务决定分片数?(模板)

你通常使用 FastAPI + PostgreSQL,当数据同步到 ES 用于搜索时,常见场景:

场景 A:商品、文章、用户搜索(经典业务)

推荐:

  • 每个索引使用 1–3 shards
  • 每 shard 目标大小 20–40GB
  • 副本 = 1

场景 B:日志 / 行为数据(常用)

采用:

  • 按天或按周滚动
  • 每个索引 1 shard(最佳!)
  • refresh_interval = 30s

场景 C:向量索引(dense_vector + knn)

  • 维度 768+ 时每 shard 控制 20GB 以下
  • shard 不宜多(knn 是每 shard 都计算)

笔记

ElasticSearch 主分片数(number_of_shards)创建后无法直接修改,需通过 _reindex_split API 重建索引;但副本数(number_of_replicas)可以动态调整。

分片类型及调整方式

  • 主分片 (Primary Shard):

    • 不可直接修改:一旦索引创建,主分片数量固定,因为数据路由基于此(_id hash % shards)。

    • 变通方法

      • 使用 _reindex API 将数据迁移到新索引(新分片数)。
      • 对于某些特定情况,可使用 _split API(将现有分片分裂为更多分片)。
  • 副本分片 (Replica Shard):

  • 可动态修改:使用 PUT /<index>/_settings API 可以随时增加或减少副本数。

示例(调整副本数)

  • 将副本数改为2
PUT /my_index/_settings
{
  "number_of_replicas": 2
}