单节点 Elasticsearch 无法支撑生产流量,但把节点连成集群只是第一步,分片怎么分配、副本怎么放、脑裂怎么防才是高可用的关键。本文从节点角色、分片分配、quorum 选举、水印机制到跨机房架构,梳理一个稳定集群的全貌。
1. 集群节点角色
1.1 角色的划分
ES 7 之后通过 node.roles 显式声明节点职责,避免一个节点既是 master 又是 data 的隐性风险。
| 角色 | 职责 | 典型数量 | 配置示例 |
|---|---|---|---|
| master | 集群元数据、分片分配决策 | 3(奇数) | master |
| data | 数据存储与查询执行 | 按容量规划 | data |
| ingest | 管道预处理 | 0-N | ingest |
| ml | 机器学习作业 | 按需 | ml |
| coordinating | 路由与聚合转发 | 2+ | 空 roles |
# elasticsearch.yml 数据节点
node.name: es-data-01
node.roles: [ data, ingest ]
cluster.name: production-cluster
network.host: 0.0.0.0
discovery.seed_hosts: ["es-master-01:9300", "es-master-02:9300", "es-master-03:9300"]
1.2 为什么需要专用主节点
数据节点的堆内存主要用于存储与查询,而 master 要维护全局元数据与分片分配状态。让大内存节点兼任 master,JVM GC 抖动会拖慢集群级的决策,因此生产环境至少部署 3 个专用 master 节点。
# 专用主节点,不存数据
node.name: es-master-01
node.roles: [ master ]
1.3 协调节点与路由
coordinating 节点接收客户端请求,解析后转发到各分片,再合并结果返回。它不做数据存储,适合承载高并发查询入口。集群可以复用 data 节点做协调,规模大时建议独立 2-3 个轻量协调节点。
2. 分片与副本
2.1 主分片与副本分片
每个索引由若干主分片(primary shard)构成,每个主分片可以有零到多个副本分片(replica shard)。副本承载读流量,并在主分片故障时晋升为新的主分片。
索引 blog(3 主分片 × 1 副本 = 6 个分片)
┌─────────────┬─────────────┬─────────────┐
│ primary 0 │ primary 1 │ primary 2 │ → 节点 A
├─────────────┼─────────────┼─────────────┤
│ replica 0 │ replica 1 │ replica 2 │ → 节点 B
└─────────────┴─────────────┴─────────────┘
副本不会与对应主分片落在同一节点
2.2 主分片数不可变
索引创建后主分片数无法修改,这是 ES 与分库分表最大的不同。主分片数决定了数据分布粒度,副本数可以随时调整。
# 创建索引:3 主分片 1 副本
curl -X PUT 'http://localhost:9200/blog?pretty' \
-H 'Content-Type: application/json' \
-d '{"settings": {"number_of_shards": 3, "number_of_replicas": 1}}'
# 调整副本数到 2
curl -X PUT 'http://localhost:9200/blog/_settings?pretty' \
-H 'Content-Type: application/json' \
-d '{"number_of_replicas": 2}'
2.3 分片数规划
| 场景 | 建议主分片数 | 说明 |
|---|---|---|
| 测试/日志 | 1-3 | 单分片免路由开销 |
| 中小业务 | 数据量 / 单分片 30GB | 分片过大影响恢复 |
| 大吞吐写入 | 节点数 × 1-3 | 摊平写入热点 |
| 超大规模 | 节点数 × 2-4 | 分片过多拖慢协调节点 |
经验公式:单分片数据量控制在 30-50GB,分片总数不超过节点数 × 10,避免协调节点聚合开销过大。分片太少则单分片过大、恢复慢;太多则集群状态臃肿。
3. 分片分配机制
3.1 分配逻辑
master 节点维护分片分配器,将未分配分片按策略放置到合适节点,考虑磁盘余量、节点属性、过滤器与并发限制。
curl -s 'http://localhost:9200/_cluster/allocation/explain?pretty' \
-H 'Content-Type: application/json' \
-d '{"index": "blog", "shard": 0, "primary": true}'
_allocation/explain API 是排查分片未分配的利器,会返回当前节点与候选节点的决策原因。
3.2 分片分配感知
跨机房或异构节点场景,用 allocation awareness 让副本与主分片分布在不同的属性域。
# elasticsearch.yml
cluster.routing.allocation.awareness.attributes: rack_id
node.attr.rack_id: rack-a
curl -X PUT 'http://localhost:9200/_cluster/settings?pretty' \
-H 'Content-Type: application/json' \
-d '{
"persistent": {
"cluster.routing.allocation.awareness.attributes": "rack_id"
}
}'
此时主分片落在 rack-a,副本会优先落到 rack-b,实现机架级容错。
3.3 分片分配过滤与平衡
curl -X PUT 'http://localhost:9200/_cluster/settings?pretty' \
-H 'Content-Type: application/json' \
-d '{
"persistent": {
"cluster.routing.allocation.exclude._name": "es-data-03"
}
}'
滚动升级或下线节点前,用 exclude 过滤逐节点排空分片,避免大范围移动引发 IO 风暴。平衡参数 cluster.routing.allocation.balance.shard 可调整分片数量均衡与磁盘均衡的权重。
3.4 延迟分配与恢复
{
"persistent": {
"cluster.routing.allocation.node_concurrent_recoveries": 4,
"cluster.routing.allocation.node_concurrent_incoming_recoveries": 2
}
}
节点重启后分片恢复默认有 1 分钟延迟,避免节点短暂抖动触发全量恢复。并发恢复数过高会抢占查询 IO,应根据磁盘性能调节。
4. 脑裂与选举机制
4.1 什么是脑裂
网络分区时,集群可能被拆成多个互相不可见的小集群,各自认为自己是主,同时接受写入,导致数据分片状态分裂。ES 7 之前用 discovery.zen.minimum_master_nodes 防脑裂。
4.2 现代选举与 quorum
ES 7 之后引入 cluster.initial_master_nodes 与基于投票的选举机制,主节点需要获得严格多数(quorum)选票才能当选。
master-eligible 节点数 = 3
quorum = 节点数 / 2 + 1 = 2
网络分区:3 节点被拆成 2 + 1
分组 2:满足 quorum(2 ≥ 2),可产生主节点
分组 1:不满足 quorum(1 < 2),降级为只读
# elasticsearch.yml 每个 master-eligible 节点
discovery.seed_hosts: ["es-master-01:9300", "es-master-02:9300", "es-master-03:9300"]
cluster.initial_master_nodes: ["es-master-01", "es-master-02", "es-master-03"]
4.3 部署奇数个主节点
| 主节点数 | quorum | 可容忍故障数 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0(防止对半分) |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
必须部署奇数个 master-eligible 节点,偶数个会在 2+2 分区时无法达成一致。生产至少 3 个,大型集群 5 个。
5. 高可用架构
5.1 跨机房与同城双活
同城双机房 + 三 master 节点是最常见的生产布局:master 分散在两个机房,第三个放在仲裁位置(如独立机房或云间)。
机房 A:master-01 + data 节点组 A
机房 B:master-02 + data 节点组 B
机房 C(仲裁):master-03(仅 master 角色)
任一机房整体故障,剩余节点仍 ≥ quorum,集群可用。
5.2 冷热分离架构
{
"persistent": {
"cluster.routing.allocation.awareness.attributes": "box_type",
"cluster.routing.allocation.awareness.force.box_type.values": ["hot", "warm"]
}
}
配合 node.attr.box_type,把热数据分片放到 SSD 节点、温数据放到大容量节点,再结合 ILM 生命周期实现数据分层。详细策略见《部署运维与备份恢复》。
5.3 节点故障恢复流程
节点宕机
│
▼
master 检测到节点离线(默认 30s 超时)
│
▼
副本分片被提升为主分片(无数据丢失)
│
▼
缺失的副本被分配到其他节点重建(网络复制)
│
▼
集群恢复 green
保证高可用的前提是每个主分片都有副本,且副本不与主分片同机。单副本下丢失一个数据节点可能丢数据,关键索引建议副本 ≥ 2。
6. 磁盘水印与只读保护
6.1 三种水印
| 水印 | 默认阈值 | 触发动作 |
|---|---|---|
| low watermark | 85% | 不再向该节点分配新分片 |
| high watermark | 90% | 尝试把分片移走 |
| flood stage | 95% | 强制所有索引只读 |
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "80%",
"cluster.routing.allocation.disk.watermark.high": "85%",
"cluster.routing.allocation.disk.watermark.flood_stage": "90%"
}
}
6.2 flood stage 的处置
达到 flood stage 后索引被置为只读,写入报 cluster_block_exception。处理步骤是先释放空间,再手动解除只读。
# 查看被锁索引
curl -s 'http://localhost:9200/_cat/indices?s=store.size:desc' | head
# 清理或扩容后解除只读
curl -X PUT 'http://localhost:9200/*/_settings?expand_wildcards=all' \
-H 'Content-Type: application/json' \
-d '{"index.blocks.read_only_allow_delete": null}'
6.3 磁盘规划经验
日志类索引建议按时序切分并配置 ILM 删除,避免无限增长触发 flood stage。主分片与副本分布在不同节点,同一分片副本不要落在同一物理磁盘。
7. 集群监控
7.1 CAT API 快速体检
curl -s 'http://localhost:9200/_cat/health?v'
curl -s 'http://localhost:9200/_cat/nodes?v'
curl -s 'http://localhost:9200/_cat/shards?v&s=prirep'
curl -s 'http://localhost:9200/_cat/allocation?v'
| 状态 | 含义 |
|---|---|
| green | 所有主分片与副本已分配 |
| yellow | 主分片已分配,副本缺失 |
| red | 存在未分配的主分片,有数据风险 |
7.2 未分配分片排查
# 查看未分配原因
curl -s 'http://localhost:9200/_cat/shards?v' | grep UNASSIGNED
# 详细解释
curl -s 'http://localhost:9200/_cluster/allocation/explain?pretty' \
-H 'Content-Type: application/json' \
-d '{"index": "blog", "shard": 2, "primary": false}'
常见原因包括节点磁盘高水位、分片数量超限、副本数设置、属性感知不匹配。修复分配后执行 _cluster/reroute 触发重分配。
7.3 集群状态缓存与慢日志
curl -s 'http://localhost:9200/_cluster/settings?pretty' | jq '.persistent'
集群状态(cluster state)每次变更全量广播,频繁创建索引会拖慢所有节点。查询慢日志与索引慢日志阈值应开启,帮助定位慢分片。
8. 总结
| 环节 | 要点 |
|---|---|
| 节点角色 | master 奇数个专用节点,data 按容量规划,coordinating 承载入口 |
| 分片规划 | 主分片数创建后不可变,单分片 30-50GB,副本数可调 |
| 分配机制 | awareness 实现机架/机房容错,explain API 排查未分配 |
| 防脑裂 | quorum 选举,master-eligible 必须奇数个 |
| 高可用 | 副本 ≥ 1 且不与主分片同机,跨机房需仲裁节点 |
| 磁盘水印 | low/high/flood 三级,95% 强制只读 |
| 监控 | CAT API 看健康,allocation explain 看原因 |
| 恢复 | 节点宕机副本晋升,并发恢复数限流防 IO 风暴 |
集群高可用的核心是分片有副本、选举有 quorum、磁盘有水位。把这些机制理解透,才能应对节点宕机、机房故障与磁盘打满三类最常见事故。分片内部的写入与查询路径可阅读《性能调优与缓存策略》,索引分层运维见《部署运维与备份恢复》。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。