本文目录导读:

Elasticsearch 的分片,这是一个非常核心且关键的概念。分片是 Elasticsearch 将索引数据分布到集群中多个节点上的基本单元。
可以把一个索引想象成一个巨大的数据库表,当这个表的数据量太大,或者查询压力太高时,单台机器无法胜任,分片就是将这个大表水平切割成多个更小的、独立的部分,每个部分就是一个分片,每个分片本身就是一个功能完整的 Lucene 索引。
下面为你详细解析 Elasticsearch 分片的核心要点、工作原理、最佳实践以及常见问题。
两种类型的分片
Elasticsearch 中有两种分片,理解它们的区别至关重要:
-
主分片 (Primary Shard)
- 定义:数据写入和读取的原始入口点。
- 作用:负责处理索引和查询请求,它是数据的“正本”。
- 数量:在创建索引时设定,并且一经设定,无法修改(除非重建索引)。 这是一个非常重要的设计决策。
-
副本分片 (Replica Shard)
- 定义:主分片的精确拷贝。
- 作用:
- 高可用性:当承载主分片的节点宕机时,副本分片可以自动提升为新的主分片,保证集群不丢失数据,服务不中断。
- 提高查询吞吐量:副本分片可以响应查询请求,高并发查询时,主、副本分片可以并行工作,大大提升搜索性能。
- 数量:可以随时动态调整,可以设置副本数为 0(节省空间,但无容错),也可以设置为 3(容错性高,但占用更多磁盘和网络资源)。
分片的核心工作原理
-
数据写入流程
- 当你向一个索引写入文档时,Elasticsearch 会通过路由算法(默认基于文档
_id的哈希值)计算该文档应该放入哪个主分片。 - 公式:
shard_num = hash(_routing) % num_primary_shards。 - 文档被写入对应的主分片,随后主分片将此操作同步到其所有副本分片,只有当主分片和所有副本分片都完成写入(或配置的
wait_for_active_shards条件满足)后,写入请求才会成功返回。
- 当你向一个索引写入文档时,Elasticsearch 会通过路由算法(默认基于文档
-
数据查询流程
- 一个搜索请求(
term,match)会广播到索引的所有主分片或副本分片上(默认是“轮询”主和副本)。 - 每个分片独立执行查询,返回自己分片内的匹配结果(即“局部结果”)。
- 协调节点负责收集所有分片返回的局部结果,进行全局合并、排序、分页,最后将最终结果返回给客户端。
- 一个搜索请求(
分片数量与副本数量的最佳实践
这是 Elasticsearch 使用中最容易出问题的地方。
主分片数量 (Primary Shards)
- 原则:设大不设小,但也不能太大。
- 设定时机:创建索引时
PUT my-index { "settings": { "number_of_shards": 3 } }。 - 推荐范围:根据你的数据量和节点数,建议每个分片的大小控制在 10GB 到 50GB 之间,最大不要超过 100GB。
- 分片太小(< 1GB):会导致“分片过多”的问题,集群管理开销(元数据、脑裂风险、搜索并发问题)巨大。
- 分片太大(> 100GB):故障恢复速度慢,重新平衡数据耗时长,搜索性能会因 I/O 瓶颈而下降。
- 计算公式参考:
- 预估总数据量:500GB。
- 目标分片大小:30GB。
- 所需主分片数量 ≈ 500GB / 30GB ≈ 16 ~ 17 个,考虑到未来的增长,你可以设成 20 个,这是一个经验值,需要根据实际硬件(磁盘和内存)调整。
副本分片数量 (Replica Shards)
- 原则与作用:性能 + 容错。
- 设定时机:随时可以调整
PUT my-index/_settings { "index.number_of_replicas": 1 }。 - 推荐值:
- 生产环境:至少设置为 1(保证任何一台机器宕机,数据不丢,查询不中断)。
- 高可用/高查询场景:如果查询压力极大,可以设置为 2 或 3,但要注意,副本数增加会占用等倍的磁盘空间和网络带宽。
- 开发/测试环境:可以设置为 0,节省资源。
分片与节点的关系(关键概念)
- 同一个分片的主副本不能存在于同一个节点上,这是 Elasticsearch 高可用的核心保证,如果主副本都在同一节点,该节点宕机,数据就全丢了。
- 尽量让分片均匀分布在所有节点上,这样才能充分利用集群的并行计算能力和存储空间。
举例:一个索引有 4个主分片,2个副本 (总共 4 * (1+2) = 12 个分片实体),运行在 3个节点 的集群上。
- 系统会自动将 12 个分片实体(4主 + 8副)均衡地分布到 3 个节点上(每个节点约 4 个分片实体)。
- 如果其中 1 个节点宕机,剩余的 2 个节点会检测到,副本分片会自动提升为新的主分片,集群仍然正常工作(只是副本数暂时变成
1甚至0)。
常见问题与陷阱
-
分片数过大
- 问题:集群元数据庞大,每个分片都需要占用文件句柄、内存、线程,搜索时协调节点需要向大量分片发起请求,网络开销和合并开销剧增。
- 解决方法:合理规划分片数;如果已经建立,可以创建新索引(调整分片数),使用 Reindex API 将老数据迁移过去。
-
分片数过小
- 问题:单个分片过大(> 200GB),索引和查询性能急剧下降;无法充分利用多台服务器资源。
- 解决方法:同样通过 Reindex 重建索引。
-
路由与分片不均衡
- 如果使用了自定义
routing值(例如按user_id路由),没有合理设置,可能导致某些分片巨大,某些分片很小(“热点”问题)。 - 解决方法:检查路由策略,或者调整分片数使其足够多来分散热点。
- 如果使用了自定义
-
分片与节点数量的平衡
- 公式建议:
节点数 × (副本数 + 1)要不大于主分片数,才能保证数据的均匀分布,5个节点,1个副本,则主分片数建议≥ 5×(1+1)=10。 否则,理论上有些节点会空闲。
- 公式建议:
调整分片(重要提醒)
- 无法直接修改:
number_of_shards一旦索引创建即锁定,无法变更。 - 如何修改:
- Reindex API:创建一个新索引(设置好
number_of_shards),将数据从旧索引通过 Reindex 迁移过去,然后将别名指向新索引,这是生产环境最标准的做法。 - Split API(Elasticsearch 6.1+):可以将主分片数量翻倍,但前提是旧索引的
index.number_of_routing_shards设置合理。 - Shrink API(Elasticsearch 5.0+):可以将主分片数量减少到某个因子,例如从 8 个缩小到 4 个或 2 个。
- Reindex API:创建一个新索引(设置好
- 分片 = 数据的基本搬运和搜索单元。
- 主分片数量 = 固定不可变;副本数量 = 可随时调整。
- 每个分片建议 10~50GB,这是一个经验法则。
- 副本 = 性能 + 容错。
- 集群规模(节点数)和分片数要匹配。
理解分片是掌握 Elasticsearch 性能调优和高可用架构的基石,在实际生产环境中,一定要在设计之初就做好规划,避免后期遇到因分片不合理导致的性能瓶颈或运维难题。