Elasticsearch 集群架构中分片和副本的作用是什么?
Elasticsearch 的分布式能力建立在两个核心机制之上:分片(Shard) 和 副本(Replica)。分片解决"一台机器存不下、算不快"的问题,副本解决"一台机器挂了数据丢了"的问题。理解这两者的工作方式,是掌握 Elasticsearch 集群架构的关键。
分片(Shard):水平拆分,并行提速
分片是将一个索引拆分为多个独立存储单元的机制。每个分片本质上是一个完整的 Lucene 索引,可以独立存储和检索数据,分布在集群的不同节点上。
水平扩展存储容量
单节点存储有上限。假设一个索引有 60GB 数据,设置 number_of_shards=5,则每个分片存储约 12GB,可分散到 5 个节点上。数据量增长时,通过增加节点即可承载更多分片。
并行提升查询性能
搜索请求到达后,协调节点将查询分发到所有相关分片并行执行,各分片返回局部结果后由协调节点合并排序。5 个分片意味着 5 路并行,查询延迟显著降低。
分片数量在索引创建时确定,不可修改
这是一个常考的面试点。主分片数一旦设定就无法更改(因为文档路由公式依赖分片数)。如果需要调整,只能通过 Reindex 重建索引。设置时需预估数据规模:
shellPUT /my_index { "settings": { "number_of_shards": 3, "number_of_replicas": 1 } }
副本(Replica):高可用与读扩展
副本是主分片的完整拷贝,与主分片存储在不同节点上。它的核心价值有两个:故障容错和读性能提升。
故障容错——节点宕机数据不丢失
当持有主分片的节点故障时,集群会自动将对应的副本提升为主分片,保证数据可继续读写。故障节点恢复后,集群会重新同步数据,恢复副本。整个过程中,用户无感知。
读请求负载均衡
读操作(搜索、聚合)可以在主分片和副本上同时执行。3 个主分片 + 1 副本 = 6 个可读分片,查询吞吐量翻倍。写操作仍然只发生在主分片上,之后异步复制到副本。
副本数量可以随时修改
与分片不同,副本数可动态调整,不需要重建索引:
shellPUT /my_index/_settings { "number_of_replicas": 2 }
分片与副本的协作机制
文档写入流程
- 客户端发送写请求到协调节点
- 协调节点根据文档 ID 计算目标分片:
shard = hash(routing) % number_of_primary_shards - 请求转发到主分片所在节点,主分片完成写入
- 主分片将数据同步到所有副本分片
- 所有副本确认后,返回成功响应给客户端
文档读取流程
- 协调节点收到读请求
- 根据路由信息确定目标分片组(主分片 + 副本)
- 采用轮询策略在主分片和副本间选择一个执行查询,实现负载均衡
- 返回结果
故障转移流程
当节点宕机时,集群执行以下步骤:
- 主节点检测到节点离线,将集群状态标记为 yellow(有副本丢失)或 red(有主分片丢失)
- 若主分片丢失,将对应副本提升为新主分片
- 在剩余节点上重新分配分片,恢复副本数量
- 数据通过副本重新同步,最终恢复为 green 状态
配置原则与最佳实践
分片数设置
- 单分片建议大小 30-50GB,不超过 50GB
- 分片数 = 预估数据量 / 单分片目标大小
- 避免过度分片:每个分片消耗内存和文件句柄,分片过多导致性能下降
- 官方建议:每个节点分片数不超过
堆内存(GB) × 20
副本数设置
- 生产环境至少 1 个副本,保证单节点故障不丢数据
- 对读吞吐要求高的场景可增加到 2 个副本
- 副本会增加存储开销和写入延迟(写操作需同步到所有副本),需要权衡
常见配置错误
- 小索引设置过多分片(如 1GB 数据设 5 个分片),浪费资源
- 副本数为 0 且只有单节点,节点故障即数据丢失
- 分片大小不均,部分热点分片成为瓶颈
面试常见追问
Q: 分片数为什么创建后不能改?
文档路由公式 hash(routing) % primary_shards 依赖分片数。如果分片数变化,已有文档的路由结果改变,查询时无法定位到正确的分片。
Q: 副本同步是同步还是异步?
写入时是同步的——主分片写入后等待所有副本确认才返回成功(可通过 consistency 参数调整)。副本之间的分段合并等操作则是异步进行。
Q: 如何选择分片数量?
基于数据量和节点数预估。核心公式:分片数 = 总数据量 / 30GB(单分片建议上限)。同时确保分片数不超过 节点数 × 每节点分片上限。实际场景中需结合写入频率和查询复杂度调整。