从硬件选型、节点角色划分、分片策略、JVM 参数四个维度梳理 ES 集群配置最佳实践,重点解决"分片数该设多少"这个高频问题。
目录
| 章节 | 说明 |
|---|---|
| 硬件选型 | 磁盘、内存、CPU 的选择建议 |
| 节点角色划分 | Master、Data、协调节点的隔离原则 |
| 分片数量规划 | 分片大小公式与规范 |
| 分片过多的代价 | 过多分片引起的扩展性问题 |
| 关键索引配置 | refresh、translog、segment 合并 |
| 集群级别参数 | 重要的 cluster settings |
硬件选型
磁盘
| 场景 | 推荐磁盘 | 说明 |
|---|---|---|
| 查询延迟敏感 | SSD / NVMe | SSD 查询速度比 SATA 快 5-10 倍 |
| 查询要求一般 | SATA | 成本低,适合冷数据 |
| 数据节点 | 单机 500G 以上 | 保证足够的存储空间 |
| 协调节点 | 200G 足矣 | 协调节点不存数据,只做路由和聚合 |
ES 最大的性能瓶颈往往是磁盘 I/O,优先解决磁盘问题。
内存
推荐配置:
物理内存 >= 16G
JVM Heap = 机器内存的 50%,但不超过 32G
内存 : 磁盘 ≈ 1 : 10(经验比例)
示例:
32G 内存 + 320G SSD → JVM 16G,OS Cache 16G,磁盘 320G
为什么 Heap 不超过 32 GB?
JVM 在 Heap ≤ 32 GB 时会启用指针压缩(Compressed OOPs),每个对象指针从 8 字节压缩为 4 字节,内存利用率更高。超过 32 GB 后指针压缩失效,反而会使实际可用内存变少。
CPU
- 数据节点需要遍历分片并做聚合,CPU 性能影响查询速度,建议 8 核以上
- 写入性能对 CPU 较为敏感,高 QPS 写入业务需要更好的 CPU
节点角色划分
| 节点类型 | 职责 | 数量建议 |
|---|---|---|
| Master 节点 | 管理集群状态(索引创建/删除、分片分配) | 固定 3 个,不随数据增长扩展 |
| Data 节点 | 存储数据,执行查询和写入 | 按数据量和负载横向扩展 |
| 协调节点 | 路由请求、汇聚结果,不存数据 | 按查询并发量配置 |
核心原则:Master 节点与 Data 节点必须隔离,防止数据节点因负载过高导致 Master 不可用,进而引发整个集群崩溃。
# Master 节点配置
node.master: true
node.data: false
# Data 节点配置
node.master: false
node.data: true
分片数量规划
官方推荐规则
1. 单个分片大小:10 GB ~ 50 GB(推荐 10-30 GB)
2. 每 GB Heap 内存对应的分片数 ≤ 20 个
3. 单节点最大分片数(cluster.max_shards_per_node)默认 1000
4. 集群合理的总分片数控制在 3000 以内(不超过 6000)
分片数计算公式
主分片数 = ceil(索引总大小 / 目标单分片大小)
示例:
预计索引大小 120 GB,目标单分片 30 GB
→ 主分片数 = ceil(120/30) = 4 个主分片
验证:
节点内存 32G → JVM Heap 16G
每 GB Heap 最多 20 个分片 → 16G × 20 = 320 个分片上限
4 个主分片 + 4 个副本 = 8 个分片,远小于 320,合理
分片大小规范
| 规范 | 数值 |
|---|---|
| 单个分片推荐大小 | 10-30 GB |
| 单个分片最大上限 | 50 GB |
| 单索引 size < 1 GB 时,主分片数 | ≤ 5(推荐) |
| 单节点数据量上限 | 2 TB |
| 单集群索引数量 | ≤ 1000(推荐) |
| 单集群总分片数 | ≤ 6000(推荐),合理值 ≤ 3000 |
分片均衡配置
防止某些节点分片过多导致流量不均:
PUT /my_index/_settings
{
"index.routing.allocation.total_shards_per_node": 2
}
分片过多的代价
当集群总分片数过大时(如 6 万+),会出现以下问题:
| 问题 | 说明 |
|---|---|
| 创建索引耗时长 | 6 万分片时创建新索引耗时超过 5 秒 |
| pending task 堆积 | Master 处理状态变更任务积压,集群被打爆 |
| 节点数受限 | 扩容节点时分片重分配耗时极长 |
| 集群资源碎片化 | 运维成本高,难以管理 |
| 重启效率低下 | 分片重新分配和恢复时间大幅增加 |
| 监控统计接口慢 | _cat/shards 等接口导致 Master 内存堆积 |
根本原因:每个分片对应一个 Lucene 实例,每个 Lucene 实例都占用文件句柄、JVM 内存和 CPU,分片数过多相当于同时运行数千个 Lucene 进程。
关键索引配置
Refresh 间隔
# 实时性要求不高时,延长 refresh 间隔,减少 segment 产生频率
PUT /my_index/_settings
{
"index.refresh_interval": "30s"
}
Translog 异步
PUT /my_index/_settings
{
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}
定期强制合并只读索引
# 历史不再写入的索引,强制合并为 1 个 segment
POST /my_index/_forcemerge?max_num_segments=1
索引排序(加速特定查询)
PUT /my_index
{
"settings": {
"index.sort.field": "createTime",
"index.sort.order": "desc"
}
}
对按 createTime 降序排列的查询,命中后可以提前终止扫描(Early Termination),大幅降低查询延迟。
集群级别参数
# elasticsearch.yml
# JVM Heap(设置为机器内存的 50%,不超过 32G)
-Xms16g
-Xmx16g
# 允许每个节点的最大分片数(默认 1000)
cluster.max_shards_per_node: 1000
# 索引 buffer(写入密集型集群可适当调大)
indices.memory.index_buffer_size: 15%
# 段合并速度(SSD 可调高)
indices.store.throttle.max_bytes_per_sec: 100mb
预热文件系统缓存
PUT /my_index/_settings
{
"index.store.preload": ["nvd", "dvd"]
}
| 文件类型 | 含义 |
|---|---|
nvd |
norms(相关度评分数据) |
dvd |
doc values(列式存储) |
vec, vex |
向量数据和 HNSW 图(向量索引专用) |
参考资料
评论 (0)
发表评论