Elasticsearch 分片(Shard) 是其分布式架构的核心机制,直接决定了系统的可扩展性、性能、高可用性。理解分片的原理、类型、分配策略和最佳实践,是构建稳定、高效 Elasticsearch 集群的关键。
本文将全面详解 Elasticsearch 分片的各个方面。
一、什么是分片(Shard)?
分片(Shard) 是 Elasticsearch 中数据的最小存储单元,每个索引被拆分为一个或多个分片,分布在集群的不同节点上。
- 主分片(Primary Shard):负责数据写入和存储。
- 副本分片(Replica Shard):主分片的拷贝,用于高可用和读负载均衡。
✅ 分片机制让 Elasticsearch 能够:
- 水平扩展(Scale Out)
- 并行处理查询
- 实现容错与高可用
二、分片的核心特性
| 特性 | 说明 |
|---|---|
| 不可变数量(主分片) | 主分片数在创建索引时设定,无法直接修改 |
| 可动态增减副本 | 副本数可随时调整:PUT /my-index/_settings { "number_of_replicas": 2 } |
| 自动分配 | 集群自动将分片分配到不同节点,避免单点过载 |
| 近实时搜索 | 每个分片独立构建倒排索引,支持快速检索 |
三、分片类型详解
1. 主分片(Primary Shard)
- 每个文档属于一个主分片。
- 写入流程:客户端 → 协调节点 → 路由到主分片 → 写入 Lucene → 同步到副本。
- 数量在索引创建时通过
number_of_shards设置。
PUT /my-index
{
"settings": {
"number_of_shards": 3
}
}
📌 主分片数一旦设定,不能更改。如需调整,必须通过
reindex创建新索引。
2. 副本分片(Replica Shard)
- 是主分片的完整拷贝。
- 提供:
- 高可用:主分片故障时,副本可提升为主。
- 读性能提升:搜索请求可负载均衡到主或副本。
- 数量可动态调整:
PUT /my-index/_settings
{
"number_of_replicas": 2
}
表示每个主分片有 2 个副本,总分片数 = 3 × (1 + 2) = 9
四、分片的工作原理
1. 数据路由(Routing)
Elasticsearch 使用以下公式决定文档存储在哪个主分片:
shard = hash(routing) % number_of_primary_shards
- 默认
routing = _id - 可自定义
routing值,控制相关数据分布在同一分片(如user_id)
PUT /orders/_doc/1?routing=user_123
{
"user_id": "user_123",
"product": "手机"
}
✅ 优势:提升局部性,减少跨分片查询。
2. 写入流程(Indexing)
- 所有写操作先发往主分片。
- 主分片成功后,再并行同步到副本(异步或同步,取决于
wait_for_active_shards)。
3. 查询流程(Search)
- 查询并行发送到所有主分片或副本分片。
- 协调节点合并结果,进行全局排序。
五、分片分配与集群管理
1. 分片分配策略
Elasticsearch 自动执行以下操作:
- 将主分片与副本分片分配到不同节点(避免单点故障)。
- 均衡各节点的分片数量(避免热点)。
- 支持节点标签(
node.attr.zone)实现机架感知。
2. 查看分片状态
# 查看所有分片
GET /_cat/shards?v
# 查看特定索引
GET /_cat/shards/my-index?v
# 详细信息
GET /_cluster/allocation/explain
输出示例:
index shard prirep state docs store node
my-index 0 p STARTED 1000 200kb node-1
my-index 0 r STARTED 1000 200kb node-2
3. 手动控制分片分配
禁用分片分配(维护时使用)
PUT /_cluster/settings
{
"transient": {
"cluster.routing.allocation.enable": "primaries"
}
}
启用后恢复
PUT /_cluster/settings
{
"transient": {
"cluster.routing.allocation.enable": "all"
}
}
强制重新平衡
POST /_cluster/reroute?retry_failed
六、分片大小与数量规划(最佳实践)
1. 单个分片建议大小
| 数据类型 | 建议大小 |
|---|---|
| 通用场景 | 10GB ~ 50GB |
| 日志类 | 20GB ~ 40GB |
| 小文档高频更新 | 可小至 5GB |
❌ 避免:
- 过小分片:增加开销(每个分片有独立 Lucene 实例)
- 过大分片:恢复慢、GC 压力大
2. 主分片数规划
公式:
主分片数 ≈ 数据总量 / 单分片目标大小
示例:
- 预估索引数据量:300GB
- 目标分片大小:30GB
- 建议主分片数:10
考虑未来增长:
- 若预计增长到 1TB,建议设为 20~30 个主分片。
3. 副本数建议
| 场景 | 建议副本数 |
|---|---|
| 开发/测试 | 0~1 |
| 生产环境 | 1~2 |
| 高可用要求 | ≥2 |
| 读多写少 | 可增至 3(提升查询吞吐) |
⚠️ 副本越多,写入开销越大(需同步更多副本)。
七、常见问题与解决方案
Q1:如何修改主分片数?
❌ 不能直接修改。
✅ 解决方案:使用 reindex 创建新索引:
POST /_reindex
{
"source": { "index": "old-index" },
"dest": {
"index": "new-index",
"op_type": "create"
}
}
# 创建新索引时指定新分片数
PUT /new-index
{
"settings": { "number_of_shards": 5 }
}
然后切换别名。
Q2:分片未分配(UNASSIGNED)怎么办?
常见原因:
- 磁盘空间不足
- 节点离线
cluster.routing.allocation.enable被禁用
排查命令:
GET /_cluster/allocation/explain
解决方案:
- 清理磁盘
- 启用分配
- 手动迁移分片
Q3:分片倾斜(Shard Skew)如何处理?
现象:某些节点分片过多,负载不均。
解决方法:
- 增加节点,触发自动再平衡。
- 使用
index.routing.allocation.total_shards_per_node限制每节点分片数。 - 优化
routing策略,避免热点 key。
Q4:分片恢复慢?
原因:
- 分片过大
- 网络带宽不足
- 节点资源紧张
优化:
- 减小分片大小。
- 调整恢复速度:
PUT /_cluster/settings { "transient": { "indices.recovery.max_bytes_per_sec": "50mb" } }
八、高级配置与调优
1. 分片预分配(Shard Allocation)
PUT /my-index/_settings
{
"index.routing.allocation.require._zone": "east"
}
支持基于节点属性分配分片。
2. 热温架构中的分片管理
- Hot 节点:SSD,存储活跃写入的分片。
- Warm 节点:HDD,存储只读的老分片。
通过 ILM 自动迁移分片:
"actions": {
"migrate": {
"enabled": true,
"node_attribute": "data",
"require": { "data": "warm" }
}
}
3. 强制合并(Force Merge)
对只读索引执行 force_merge,减少 segment 数量,提升查询性能:
POST /my-index/_forcemerge?max_num_segments=1
适用于日志类索引归档后。
九、总结:分片设计 checklist ✅
| 项目 | 建议 |
|---|---|
| 主分片数 | 根据数据量预估,避免过小或过大 |
| 副本数 | 生产环境 ≥1,读多可增至 2~3 |
| 分片大小 | 控制在 10~50GB |
| 路由策略 | 高频关联查询使用自定义 routing |
| 监控 | 定期检查 _cat/shards、磁盘、负载 |
| 扩容 | 通过 reindex 或 ILM 滚动实现 |
十、扩展建议
- 使用 Index Lifecycle Management (ILM) 自动管理分片生命周期。
- 结合 CCR(Cross-Cluster Replication) 实现跨集群分片复制。
- 对超大索引考虑使用 data stream(日志场景)。
- 监控
jvm.memory、thread_pool避免分片过多导致资源耗尽。
3916

被折叠的 条评论
为什么被折叠?



