面试考察点
- 是否理解索引、主分片、副本分片与节点的关系。
- 能否说明分片过大和过小的不同成本。
- 是否根据容量、查询并发和恢复时间做规划。
核心答案
主分片决定数据水平切分,副本提供冗余并可分担查询。分片数要让单分片大小、节点分布和故障恢复时间可控,同时避免大量小分片消耗堆、文件句柄和调度资源;副本数根据可用性、查询吞吐与存储成本选择。
主分片数量不是“节点数乘某个固定值”,应使用真实文档、映射和查询压测估算。
规划方法
根据保留周期估算总数据与增长,设计 rollover 阈值让分片大小稳定。确保任一数据节点故障后其余节点仍有磁盘和计算余量接收恢复分片,并把副本分布到不同故障域。
分片内部不只是一个文件
每个主分片本质上是独立的 Lucene 索引,写入先形成内存 buffer 和 segment,后台再 merge。分片越多,查询一次需要扇出的 Lucene 实例越多,打开的 segment、文件句柄、线程和 heap 元数据也越多;分片越大,单分片恢复、迁移、merge 和故障重建时间越长。
因此“分片越小越并行”与“分片越大越少开销”之间要平衡。时间序列可以按 rollover 控制单分片规模,而不是先固定一个看似漂亮的每天分片数。
容量估算示例
假设每天原始数据 500 GB,压缩和 _source 后约 350 GB,计划保留 30 天,目标单分片 30–50 GB:
总逻辑数据 ≈ 10.5 TB
主分片数 ≈ 210~350(按全周期总量)
实际还要拆成按天/周的索引、考虑副本倍数、磁盘水位、merge 临时空间、快照和故障期间剩余节点容量。不要把理论压缩比直接当生产容量保证,应从真实 mapping 和 _source 测量。
副本的两个作用
副本第一作用是容灾:主分片故障后可提升为主;第二作用是并行读:搜索请求可在主或副本之间选择。副本越多,读吞吐和故障冗余可能提高,但写入必须复制到更多分片,存储、网络、恢复和 merge 成本同步上升。
副本不能替代备份。误删、错误更新和整个集群损坏会同步到副本,必须使用快照、跨集群复制或可重放原始事件。
分配与故障域
配置 allocation awareness 或 zone/rack 感知,避免同一主分片和副本落在同一物理故障域。磁盘水位、节点角色、过滤规则、分片大小和恢复限速都会影响分配;状态黄色通常表示主已分配但副本未分配,红色则有主分片缺失。
恢复期间不要只看“集群状态变绿”,还要看恢复流量对在线查询、磁盘和网络的影响。滚动重启应逐节点操作,保证剩余副本和容量足够。
主分片调整方式
副本数可动态改;主分片数通常需要 split、shrink 或 reindex 到新索引。split 需要预留分裂因子,shrink 往往要求源索引只读并把分片集中到少数节点。时间序列更推荐通过新索引模板和 alias/数据流切换,避免改造巨型在线索引。
调整边界
副本数可动态调整,主分片数通常不能直接修改,可通过 split、shrink 或 reindex 到新索引改变。时间序列使用索引模板、ILM 和别名让新索引采用新规划。
常见误区
更多分片可能提高有限并行度,也会让每次查询扇出更多任务并增加协调开销。副本能提高读吞吐,但写入也必须同步到副本,会增加写放大。
高频追问与参考回答
追问:为什么集群是黄色状态?
通常表示主分片已分配但部分副本无法分配,常见原因是节点不足、磁盘水位、分配规则或同节点不能放同分片副本。
追问:副本数设为 0 可以吗?
单节点开发或可重建的临时数据可以,但生产意味着节点故障时主分片不可用,且没有副本分担查询。是否可接受应由 RTO/RPO 和数据是否可从事实源重建决定。
追问:为什么分片不是越多越好?
每次查询、恢复、merge 和集群状态管理都要处理更多分片,heap 与文件句柄增加,扇出和长尾更明显。分片数应基于容量与并行需求规划。
追问:副本能解决写入热点吗?
不能。写入先由主分片处理,副本复制会增加成本;热点写入需要调整 routing、拆分索引或改变数据模型。
总结
分片设计围绕单分片规模、扇出成本和恢复时间,副本设计围绕可用性与读写成本,二者都要靠压测和生命周期治理。
机制全景图
下面把「Elasticsearch 分片和副本应该如何设计?」从输入到结果压缩成一条可复述的主链路。面试时先用图建立全局坐标,再进入局部实现,能避免只背零散结论。
flowchart LR
A["路由文档到主分片"]
A --> B["主分片校验并写入"]
B --> C["并行复制到副本"]
C --> D["搜索协调各分片"]
D --> E["故障后副本晋升与重分配"]
完整链路:从输入到结果
沿着「路由文档到主分片 → 主分片校验并写入 → 并行复制到副本 → 搜索协调各分片 → 故障后副本晋升与重分配」观察输入、状态与输出,下面每个阶段都对应一个可以在源码、日志或系统表中验证的位置。
1. 路由文档到主分片
routing 值经哈希映射到固定主分片,主分片数通常不能简单原地修改。
2. 主分片校验并写入
主分片确定操作顺序并执行版本检查,然后把操作复制给当前 in-sync 副本。
3. 并行复制到副本
副本提高可用性并可服务搜索,但不会拆分单主分片的写入容量。
4. 搜索协调各分片
协调节点向每个相关分片发查询,再合并 top hits 或聚合;分片越多扇出成本越高。
5. 故障后副本晋升与重分配
节点故障后合格副本晋升,新副本恢复会占用网络、磁盘和 CPU。
源码与实现定位
| 入口 | 阅读重点 |
|---|---|
| OperationRouting | routing 到分片 |
| _cat/shards/_cluster/allocation/explain | 分片与恢复 |
源码或系统表应按上表顺序追踪:先确认入口实际走到哪条路径,再用运行时数据验证,而不是仅凭类名或配置推测。
参数配置与可复现实验
GET _cat/shards?v&h=index,shard,prirep,state,store,node
按 5/20/100 分片回放相同数据与并发,比较扇出、堆和恢复时间。
验证步骤与预期结果
1. 固定输入和基线
先在没有故障注入的环境执行上述配置,固定数据规模、并发度、运行时版本和预热时间。以「每请求分片数」为主基线,记录值应满足「记录稳态基线」;同时保存 分片大小与数量、主副本写延迟,使后续变化能够回到同一时间轴比较。
2. 从实现入口确认路径
在「OperationRouting」确认请求确实进入「routing 到分片」对应的实现,再沿「_cat/shards/_cluster/allocation/explain」观察「分片与恢复」。如果入口路径都未命中,就不应继续调整下游参数,而应先检查调用条件、版本或路由是否与假设一致。
3. 注入本文特有的失败模式
优先复现「把副本当写扩展」,并把单一变量逐级放大,直到「每请求分片数」越过「超过基线2倍」。随后再分别验证「过度分片消耗堆与协调开销」和「自定义 routing 形成热点分片」,三类故障分开执行,避免多个变量同时变化而无法归因。
4. 执行止损和根因修复
第一轮只应用「按目标 10-50GB 分片验证」,确认它能控制影响范围;第二轮应用「副本跨故障域」,验证核心链路恢复;最后落实「治理小分片」,消除同类问题再次出现的条件。每一步都保留变更前后数据,不用“感觉变快了”替代测量。
5. 通过退出条件
实验只有同时满足三项才算通过:「每请求分片数」回到「记录稳态基线」、「P99」回到「小于业务预算」、「结果差异」回到「0」,并且业务结果差异为零。若性能恢复但结果不一致,仍应视为失败;若指标恢复后很快再次越线,则说明只完成了临时止损,没有消除根因。
量化基线
| 指标 | 样例基线/口径 | 风险线 | 结论 |
|---|---|---|---|
| 每请求分片数 | 记录稳态基线 | 超过基线2倍 | 按实现入口定位 |
| P99 | 小于业务预算 | 突破预算 | 停止扩量 |
| 结果差异 | 0 | 任意非零 | 回滚并重建 |
这些数值是实验口径或示例告警线,不是可复制到所有系统的固定答案;上线阈值应由本系统稳态、峰值和故障演练共同确定。
事故复盘:索引按天创建 20 个主分片导致小集群不稳定
每日数据只有几 GB,却累计数万个小分片,Cluster State、文件句柄和堆开销远大于数据本身。通过模板减少主分片、ILM rollover 按大小滚动并合并历史索引后恢复。
| 失败模式 | 首要证据 | 第一处置动作 |
|---|---|---|
| 把副本当写扩展 | 分片大小与数量 | 按目标 10-50GB 分片验证 |
| 过度分片消耗堆与协调开销 | 主副本写延迟 | 副本跨故障域 |
| 自定义 routing 形成热点分片 | 查询分片扇出 | 治理小分片 |
发布与回滚检查点
- 发布前:确认「OperationRouting」对应实现和上述配置在目标版本仍然有效,并保存「每请求分片数」基线。
- 灰度中:同时观察 分片大小与数量、主副本写延迟、查询分片扇出;任一指标越过表中风险线,就停止继续扩量。
- 回滚时:先执行「按目标 10-50GB 分片验证」控制影响,再回退代码或参数;涉及持久状态时必须额外核对结果差异。
- 发布后:至少覆盖一个完整峰值周期,确认「把副本当写扩展」没有再次出现,才关闭变更观察窗口。
方案对比与选型
| 方案 | 更适合的场景 | 主要收益 | 代价与边界 |
|---|---|---|---|
| 增加主分片 | 单索引数据/写吞吐需并行 | 扩展写入和数据分布 | 查询扇出与固定开销增加 |
| 增加副本 | 读吞吐和高可用 | 搜索副本与故障接管 | 存储、复制与恢复成本 |
| 拆索引/时间流 | 生命周期与租户边界明确 | 易管理冷热和删除 | 跨索引查询与模板治理 |
选型至少带上 文档规模、分片数、字段基数、查询并发和写入速率,并用上面的量化基线验证;未知数据应明确为待测假设。
设计边界与工程取舍
分片是 Lucene 实例和故障恢复单位,不是免费并行度;目标应是可恢复、大小合理且数量可控的分片。
工程落地遵循:先设计 Mapping 与分片,再优化查询;任何调优都要控制扫描与内存放大。回答时直接引用「OperationRouting」、配置实验和事故数据,比复述固定模板更有说服力。