ElasticSearch 分片
ES 的性能、稳定性、扩展性,90% 取决于分片规划。
ElasticSearch 一个索引由多个分片组成:
| 类型 | 功能 |
|---|---|
| Primary Shard(主分片) | 实际写入数据 |
| Replica Shard(副本) | 容灾 + 提高查询性能 |
每个分片本质上是一个 Lucene Index(底层最小单元)。
ES 只做 “分布式调度”,真实存储由 Lucene 完成。
错误的分片数量会导致:
- 性能崩溃(太多 shard -> JVM 内存暴涨)
- 查询变慢(Broadcast 查询)
- 集群重启慢、恢复慢
- 数据迁移慢
- 写入吞吐下降
- 集群频繁不稳定(yellow、red)
分片反模式是 ES 最常见的集群故障源头。
核心公式:
✅ 每个 Shard 的理想大小:30 ~ 50GB
原因:
- 分片太小:浪费内存、CPU、filehandle
- 分片太大:迁移慢、恢复慢、merge 巨慢
✅ 分片数量计算公式
假设一个索引未来 1 年最多:
- 数据:2 TB
- 采用每 shard 40GB
2000GB / 40GB = 50 个 shard
如果集群有 3 个 data 节点:
每节点 ≈ 16–17 个 shard(正常)
| 数据量(索引) | 推荐 primary shard |
|---|---|
| < 50GB | 1 shard(最佳) |
| 50–200GB | 2–4 shards |
| 200–500GB | 4–10 shards |
| >500GB | 10+ shards(按 40GB/shard 或 ILM 滚动) |
例如你有 10 shard,一个查询会广播到所有 shard:
- 10 个 shard -> OK
- 2000 个 shard -> GG(爆炸式变慢)
每 shard 都需要:
- 文件句柄(file handle)
- JVM segment metadata
- Lucene 索引结构
结论:
Shard 不是越多越好,越少越强。
更多 shard = 更多 Lucene 索引 -> 慢。
Lucene 写入时会不断产生小 segment,后续自动 merge。
Shard 越多 -> merge 越多 -> IO 延迟暴增。
副本 = 高可用 + 查询读负载能力
建议:
| 场景 | 副本 |
|---|---|
| 写入密集(日志) | 0(写入高峰时),正常时 1 |
| 普通业务 | 1 |
| 高读取量(搜索类) | 2–3 |
经验值:
每节点 shard 数 ≤ 20 × CPU核心数
例如:
- 8 核节点:最多 ≈ 160 shards
- 16 核节点:最多 ≈ 320 shards
超过这个通常会抖动甚至频繁 GC。
适合日志系统、ES 官方推荐:
- Hot Node:SSD,存放最近 7 天
- Warm Node:普通 SSD,大量数据
- Cold Node:低成本存储
ES 支持:
条件:
- 只能从多个 shard -> 1 shard
- 索引必须是只读
示例:
POST logs-2025-01/_shrink/logs-2025-01-single
条件:
- 原 shard 数量必须是扩大后的整除关系
例如 2 -> 4 -> 8 可以,但 3 -> 5 不行。
适用于日志、订单、行为数据:
使用 ILM:
当 index.size > 40GB -> 自动 rollover
优点:
- 不必一次性规划无限大的分片数
- 每天/每周一个索引,天然分片
- 数据可按生命周期自动删除(delete phase)
| ❌ 反模式 | 危害 |
|---|---|
| 给每个用户建一个 index | field explosion + shard explosion |
| 给每个用户建一个 shard | 直接爆炸 |
| 1TB 数据用 1 shard | 迁移灾难 |
| 一个索引 2000 shards | 查询、内存全部崩溃 |
| 频繁 split、shrink shard | 会导致中断和性能下降 |
| log/behavior 不按日期切分 | 巨无霸 shard |
| ES 当 OLTP 用 | 大量写入 + 分片频繁更新灾难 |
你通常使用 FastAPI + PostgreSQL,当数据同步到 ES 用于搜索时,常见场景:
推荐:
- 每个索引使用 1–3 shards
- 每 shard 目标大小 20–40GB
- 副本 = 1
采用:
- 按天或按周滚动
- 每个索引 1 shard(最佳!)
- refresh_interval = 30s
- 维度 768+ 时每 shard 控制 20GB 以下
- shard 不宜多(knn 是每 shard 都计算)
ElasticSearch 主分片数(number_of_shards)创建后无法直接修改,需通过 _reindex 或 _split API 重建索引;但副本数(number_of_replicas)可以动态调整。
-
主分片 (Primary Shard):
-
不可直接修改:一旦索引创建,主分片数量固定,因为数据路由基于此(_id hash % shards)。
-
变通方法:
- 使用
_reindexAPI 将数据迁移到新索引(新分片数)。 - 对于某些特定情况,可使用
_splitAPI(将现有分片分裂为更多分片)。
- 使用
-
-
副本分片 (Replica Shard):
-
可动态修改:使用
PUT /<index>/_settingsAPI 可以随时增加或减少副本数。
示例(调整副本数)
- 将副本数改为2
PUT /my_index/_settings
{
"number_of_replicas": 2
}