Elasticsearch 学习笔记(五):集群与运维

写在前面

本文是 Elasticsearch 学习笔记系列的最后一篇,介绍集群架构、节点角色、分片分配、索引生命周期管理和运维监控。前置知识:进阶查询与优化(第四篇)。


一、集群架构

1.1 节点角色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Master 节点(master)
  - 管理集群元数据(索引、Mapping、分片位置)
  - 不参与数据存储和查询
  - 生产环境建议 3 个专用 Master 节点(避免脑裂)

Data 节点(data)
  - 存储数据和执行查询
  - 最核心的节点,IO 和 CPU 消耗最大
  - 根据数据量增加 Data 节点

Coordinating 节点
  - 接收客户端请求,分发到 Data 节点,汇总返回
  - 不存储数据,不做 Master
  - 适合做查询入口,减轻 Data 节点压力

Ingest 节点(ingest)
  - 数据预处理(Pipeline)
  - 类似 Logstash 的功能

ML 节点(ml)
  - 机器学习任务(异常检测等)

1.2 最小生产集群

1
2
3
3 Master 节点   — 高可用(2 个挂了还能选主)
3 Data 节点     — 数据存储和查询(副本需要 3 节点)
2 协调节点      — 查询入口(可选)

1.3 配置节点角色

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# elasticsearch.yml

# Master 节点
node.roles: [master]

# Data 节点
node.roles: [data]

# 协调节点
node.roles: []

# Data + Master(小规模,合一部署)
node.roles: [data, master]

# Data Hot / Warm / Cold(冷热分层)
node.roles: [data_hot]
node.roles: [data_warm]
node.roles: [data_cold]

二、分片和副本

2.1 分片分配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
创建索引时指定分片数:
  PUT /products
  {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1
    }
  }

  3 个主分片 + 3 个副本分片 = 6 个分片

  分片分配规则:
  - 主分片和副本不在同一节点
  - 尽量均匀分布到各节点
  - 分片数创建后不能修改(只能 reindex)

2.2 副本的作用

1
2
3
4
5
6
7
1. 高可用    — 主分片挂了,副本自动提升为主
2. 负载均衡  — 查询可以命中主分片或副本(读性能翻倍)
3. 容灾      — 节点故障不影响数据完整性

副本数可以动态调整:
  PUT /products/_settings
  { "number_of_replicas": 2 }

2.3 分片数规划

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
经验值:
  每个分片 10-50GB
  每个节点不超过 20 个分片/GB 堆内存

计算:
  数据量 100GB,每分片 30GB → 4 个主分片
  3 节点集群 → 每个节点约 1-2 个主分片 + 副本

避免:
  - 分片太小(< 1GB)→ 集群管理开销大
  - 分片太大(> 50GB)→ 恢复慢,查询慢
  - 分片数过多(> 1000/节点)→ 内存压力

三、分片分配策略

3.1 分片过滤

1
2
3
4
5
6
7
8
9
// 节点级别打标签
// elasticsearch.yml
// node.attr.box_type: hot

// 索引分配到指定节点
PUT /products/_settings
{
  "index.routing.allocation.require.box_type": "hot"
}

3.2 冷热架构

1
2
3
4
5
6
7
8
9
// Hot 节点:SSD,存储近期热数据
// Warm 节点:HDD,存储较冷数据
// Cold 节点:低成本存储,归档数据

// 索引从热迁移到温
PUT /products-2026-03/_settings
{
  "index.routing.allocation.require.box_type": "warm"
}

四、索引生命周期管理(ILM)

4.1 ILM 策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "30gb",
            "max_age": "7d"
          },
          "set_priority": { "priority": 100 }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": { "number_of_shards": 1 },
          "forcemerge": { "max_num_segments": 1 },
          "allocate": {
            "require": { "box_type": "warm" }
          },
          "set_priority": { "priority": 50 }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "require": { "box_type": "cold" }
          },
          "set_priority": { "priority": 0 }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
生命周期阶段:
  hot     — 活跃数据,频繁读写,SSD 存储
  warm    — 较少查询,只读,HDD 存储
  cold    — 极少查询,低成本存储
  delete  — 过期删除

触发条件(rollover):
  max_primary_shard_size  — 主分片达到大小
  max_age                — 索引存在时间
  max_docs               — 文档数量

自动操作:
  rollover     — 滚动创建新索引
  shrink       — 减少分片数(冷数据不需要多分片)
  forcemerge   — 合并 Segment(减少文件数)
  allocate     — 迁移到指定节点
  delete       — 删除索引

4.2 使用 ILM

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 索引模板中关联 ILM 策略
PUT /_index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy",
      "index.lifecycle.rollover_alias": "logs"
    }
  }
}

// 创建第一个索引
PUT /logs-000001
{
  "aliases": {
    "logs": { "is_write_index": true }
  }
}
// 写入 logs 别名 → 自动写入 logs-000001
// 7 天后或 30GB → 自动创建 logs-000002 → 切换写入
// 30 天后 → 迁移到 warm 节点
// 90 天后 → 自动删除

五、集群监控

5.1 集群健康

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 集群整体健康
GET /_cluster/health
// status: green / yellow / red
// green  — 所有主分片和副本都正常
// yellow — 所有主分片正常,部分副本缺失
// red    — 部分主分片不可用(数据丢失风险)

// 节点状态
GET /_cat/nodes?v
// 显示:name, ip, heap.percent, ram.percent, cpu, load_1m, node.role

// 分片状态
GET /_cat/shards?v
// 显示哪些分片在哪个节点,是否正常

// 未分配分片
GET /_cat/shards?v&h=index,shard,pristate,state,unassigned.reason&s=state

5.2 索引监控

1
2
3
4
5
6
7
8
// 索引大小和文档数
GET /_cat/indices?v&h=index,docs.count,store.size,pri.store.size&s=store.size:desc

// 索引健康
GET /_cluster/health?level=indices

// 分片详情
GET /_cat/shards/products?v

5.3 性能指标

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 搜索性能
GET /_stats/search?human

// 索引性能
GET /_stats/indexing?human

// 合并性能
GET /_stats/merges?human

// 段信息
GET /products/_segments

5.4 慢查询日志

1
2
3
4
5
6
7
8
9
// 开启慢查询日志
PUT /products/_settings
{
  "index.search.slowlog.threshold.query.warn": "5s",
  "index.search.slowlog.threshold.query.info": "2s",
  "index.search.slowlog.threshold.fetch.warn": "1s",
  "index.indexing.slowlog.threshold.index.warn": "10s"
}
// 超过阈值的查询会记录到慢查询日志

六、备份和恢复

6.1 创建快照仓库

1
2
3
4
5
6
7
8
// 注册仓库(文件系统)
PUT /_snapshot/my_backup
{
  "type": "fs",
  "settings": {
    "location": "/data/es_backup"
  }
}

6.2 创建快照

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 备份指定索引
PUT /_snapshot/my_backup/snapshot_20260530
{
  "indices": "products,orders",
  "ignore_unavailable": true,
  "include_global_state": false
}

// 备份所有索引
PUT /_snapshot/my_backup/snapshot_all

// 查看快照进度
GET /_snapshot/my_backup/snapshot_20260530/_status

// 查看所有快照
GET /_cat/snapshots/my_backup?v

6.3 恢复

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 从快照恢复
POST /_snapshot/my_backup/snapshot_20260530/_restore
{
  "indices": "products",
  "index_settings": {
    "index.number_of_replicas": 1
  }
}

// 恢复到新索引名
POST /_snapshot/my_backup/snapshot_20260530/_restore
{
  "indices": "products",
  "rename_pattern": "(.+)",
  "rename_replacement": "$1_restored"
}
// 恢复为 products_restored

七、常见运维操作

7.1 节点维护

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 排空节点上的分片(维护前)
PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": "192.168.1.100"
  }
}
// ES 会自动将该节点上的分片迁移到其他节点
// 迁移完成后可以安全停机

// 维护完成后恢复
PUT /_cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": null
  }
}

7.2 索引操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 强制合并段(减少 Segment 数量,降低资源消耗)
POST /products/_forcemerge?max_num_segments=1
// 适合只读索引

// 清理缓存
POST /products/_cache/clear

// 刷新
POST /products/_refresh

// 刷盘
POST /products/_flush

7.3 Reindex(重建索引)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 从旧索引重建到新索引(修改 Mapping 后常用)
POST /_reindex
{
  "source": { "index": "products-v1" },
  "dest":   { "index": "products-v2" }
}

// 带查询条件重建
POST /_reindex
{
  "source": {
    "index": "products-v1",
    "query": {
      "range": { "created_at": { "gte": "2026-01-01" } }
    }
  },
  "dest": { "index": "products-v2" }
}

// 远程集群重建(迁移数据)
POST /_reindex
{
  "source": {
    "remote": {
      "host": "http://old-cluster:9200"
    },
    "index": "products"
  },
  "dest": { "index": "products" }
}

八、常见问题排查

8.1 集群 Red

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
1. 查看哪个索引有问题
   GET /_cluster/health?level=indices

2. 查看未分配的分片
   GET /_cat/shards?v&h=index,shard,prirep,state,unassigned.reason

3. 查看未分配原因
   GET /_cluster/allocation/explain

4. 常见原因:
   - 节点宕机
   - 磁盘满了(水位超过 flood-stage)
   - 副本数超过节点数

8.2 磁盘水位

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
ES 磁盘水位阈值:
  cluster.routing.allocation.disk.watermark.low:    85%(默认)
    → 不再分配新分片到该节点

  cluster.routing.allocation.disk.watermark.high:    90%(默认)
    → 开始迁移该节点上的分片

  cluster.routing.allocation.disk.watermark.flood_stage: 95%(默认)
    → 所有索引设为只读

恢复方法:
  1. 清理磁盘空间
  2. 解除只读
     PUT /products/_settings
     { "index.blocks.read_only_allow_delete": null }

8.3 性能慢

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
排查思路:
1. 是写入慢还是查询慢?
   GET /_stats/indexing,search?human

2. 查看慢查询日志
   检查 ES 日志目录中的慢查询记录

3. 检查 JVM 堆内存
   GET /_cat/nodes?v&h=name,heap.percent,ram.percent,cpu
   堆使用 > 85% → 增加 JVM 内存或优化查询

4. 检查 GC 情况
   GET /_nodes/stats/jvm?filter_path=*.jvm.gc

5. 检查线程池
   GET /_cat/thread_pool?v&h=node_name,name,active,rejected,completed
   rejected > 0 → 请求被拒绝,需要优化或扩容

九、系列总结

9.1 知识体系回顾

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
第一篇:基础入门
  - 核心概念、倒排索引、索引管理、Mapping

第二篇:文档操作与搜索
  - CRUD、Bulk、全文搜索、精确搜索、bool 复合查询

第三篇:聚合分析
  - 指标聚合、桶聚合、嵌套聚合、实战场景

第四篇:进阶查询与优化
  - 深度分页、分词器、中文分词、评分调优、性能优化

第五篇:集群与运维
  - 节点角色、分片分配、ILM、监控、备份恢复

9.2 核心要点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
1. ES 的核心是倒排索引,理解它就理解了搜索的本质
2. Mapping 要提前设计,生产环境不要依赖动态映射
3. text 字段做全文搜索,keyword 字段做精确匹配和聚合
4. 查询条件用 filter 不用 must(性能差距显著)
5. 中文场景必须用 IK 分词器
6. 深分页用 search_after,不要用 from/size
7. 日志类数据用 ILM 自动管理生命周期
8. 分片规划:每分片 10-50GB,不要太多也不要太少
9. 集群至少 3 个 Master 节点保证高可用
10. 磁盘水位和 JVM 堆内存是最常出问题的地方