4. 分片与副本的高可用工程

分片与副本是 Elasticsearch 高可用的物理基础。主分片决定数据能否写入与水平扩展能力,副本分片决定节点故障时数据是否仍可读、能否快速接管。工程上真正难的不是“把副本数设成 2”,而是让分片在节点间合理分布、大小可控、故障后能有序恢复,并且在网络分区时避免出现两个主节点同时接受写入的脑裂局面。

一、分片分配策略:让分片落在正确的位置

分配由主节点负责决策,核心约束来自分配感知(awareness)、过滤规则(filtering)和磁盘水位。分配感知通过 cluster.routing.allocation.awareness.attributes 指定属性(如 zone、rack),同一分片的主副本会被强制分散到不同属性值;若某属性值节点全部离线,可配合 force.zone.values 允许副本临时落到剩余区域,避免分片无法分配。

过滤规则用于把索引“钉”在特定节点上,例如冷热分层:热节点打 node.attr.tier: hot,冷节点打 tier: cold,索引创建时用 index.routing.allocation.include.tier 指定。磁盘水位是硬约束:低于 low(默认 85%)不再新分配,超过 high(默认 90%)尝试迁走分片,超过 flood_stage(默认 95%)索引转为只读。工程上应把水位与节点磁盘容量一起规划,而不是等告警后再清理。

二、副本数选择:可用性与成本的平衡

副本数 number_of_replicas 决定每个主分片有几份冗余。单节点集群设副本无意义;3 个数据节点、1 副本可容忍 1 个节点故障;若要求容忍 2 个节点同时故障,至少需要 2 副本且节点数不少于 3。副本还承担读吞吐:查询会轮询主副本,副本越多读能力越强,但写入需同步到所有副本,写放大和刷新开销随之上升。

一个常见误区是“副本数等于节点数就安全”。实际上副本分配受感知属性约束,若 3 个节点同处一个机架,机架断电仍会整体不可用。因此副本数必须与故障域一起设计:跨机架、跨可用区部署时,副本数至少覆盖最大可容忍故障域数量。

三、分片大小控制:避免“大分片”与“小分片”两个极端

官方经验是单个分片 10~50GB 较为健康,搜索类场景可更小,日志类可接近上限。分片过大导致恢复慢、单分片查询延迟高、重新分配代价大;分片过小则集群元数据膨胀、每分片固定开销累积。估算公式可简化为:

主分片数 ≈ 索引总数据量 / 目标分片大小
例如:总数据 600GB,目标 30GB/分片 → 主分片数 ≈ 20

分片数在索引创建后不可直接修改(只能 _shrink 或 _split),因此要预留增长空间。对按天滚动的日志索引,可用 ILM 在 rollover 时按大小或文档数触发新索引,把“分片大小控制”变成持续动作而非一次性设置。

分片分配 · 副本冗余 · 恢复与脑裂防护 数据节点(3 节点 / 2 可用区) node-1 · zone=A · hot P0 主分片 30GB R1 副本 30GB P1 主分片 · 30GB 磁盘水位 78% · 正常 node-2 · zone=B · hot R0 副本 30GB P2 主分片 30GB R2 副本 · 30GB 磁盘水位 81% · 正常 node-3 · zone=A · warm P3 主分片 28GB R3 副本 28GB 磁盘水位 93% · 触发 high 迁移 分片将迁往低水位节点 分配约束(主节点决策依据) awareness: zone filter: tier=hot/cold 水位 85/90/95% 同分片主副本异区 故障恢复流程(node-1 失联) ① 节点失联 master 标记离线 ② 提升副本 R0/R1 转主分片 ③ 重新分配 副本补到其他节点 ④ 分片恢复 peer recovery 同步 ⑤ 状态转绿 _cluster/health 脑裂防护:quorum = 主节点数 / 2 + 1 3 主节点 → quorum=2;2 主节点 → quorum=2(无容错);建议奇数主节点,discovery.seed_hosts 固定种子,避免网络分区两侧各自选主。 少数派拒绝写入

四、分片恢复流程:从失联到转绿

当数据节点失联,主节点先将其标记为离线,并把该节点上的主分片对应的副本提升为新的主分片,保证写入不中断。随后触发分片重新分配,把缺失的副本补到其他节点。恢复分两种:peer recovery 从同分片的其他副本复制段文件,速度快;snapshot recovery 从快照仓库恢复,适合跨集群或大分片。恢复期间可通过 _cat/recovery?v 观察 stage(index、translog、finalize)和 bytes_percent。

恢复会占用网络与磁盘 IO,若同时恢复大量分片会拖慢集群。可通过 cluster.routing.allocation.node_concurrent_recoveries(默认 2)和 indices.recovery.max_bytes_per_sec(默认 40MB/s)限流。判断恢复是否健康,看 _cluster/health 的 active_shards_percent 是否回到 100%、unassigned_shards 是否归零,以及 _cat/recovery 中是否还有长时间停留在 translog 阶段的分片。

五、脑裂风险规避

脑裂指网络分区后两侧都认为自己是主节点,各自接受写入,导致数据分叉。Elasticsearch 7.x 以后用基于 quorum 的选举:主节点数 N,法定票数为 N/2 + 1。3 个主节点时 quorum=2,少数派一侧无法选出主节点,只能拒绝写入,从而避免双主。2 个主节点时 quorum 仍为 2,任何一台故障都会失去写入能力,因此生产环境建议至少 3 个专用主节点且为奇数。

配置上要固定 discovery.seed_hosts 与 cluster.initial_master_nodes(仅首次启动),避免节点自行组网;跨机房部署时把主节点集中在同一低延迟区域,数据节点可跨区,但不要跨高延迟链路做选举。若使用云托管服务,应确认其主节点拓扑与故障域隔离策略。

工程检查顺序:先确认主节点数为奇数且 quorum 可容忍目标故障数,再核对 awareness 与过滤规则是否让主副本跨故障域,然后按 10~50GB 目标反推主分片数,最后用 _cat/recovery 与 _cluster/health 验证恢复闭环。
参数典型值作用与判断
number_of_replicas1~2决定可容忍节点故障数与读吞吐
目标分片大小10~50GB过大恢复慢,过小元数据膨胀
node_concurrent_recoveries2限制并发恢复,保护 IO
max_bytes_per_sec40MB/s恢复带宽上限,按网络调整
主节点数 / quorum3 / 2奇数部署,避免脑裂与写入中断

把以上五点串起来,分片与副本的高可用就不是单点配置,而是一套从拓扑、参数到恢复验证的工程闭环:分配策略决定“放哪里”,副本数决定“坏多少还能活”,分片大小决定“恢复多快”,恢复流程决定“故障后多久转绿”,脑裂防护决定“分区时会不会写坏数据”。