Elasticsearch 集群
Elasticsearch 集群通过节点、分片和副本实现水平扩展和高可用。理解集群结构,是排查搜索慢、索引 red/yellow、分片未分配、磁盘水位和写入抖动的基础。
商业系统里,商品搜索、订单检索、日志检索对集群的要求并不一样:商品搜索更关注查询稳定性和相关性,订单检索更关注权限过滤和时间范围,日志检索更关注写入吞吐、时间滚动索引和磁盘生命周期。
为什么 ES 要拆分片和副本
单台机器的 CPU、内存、磁盘和 IO 都有限。ES 通过主分片把一个索引拆到多台机器上,从而提升容量和并行处理能力;通过副本分片复制数据,提升查询能力和故障恢复能力。
如果没有分片,数据量大了只能垂直扩容;如果没有副本,一个节点故障就可能导致数据不可用。
flowchart TD
A["product_search 索引"] --> B["主分片 P0"]
A --> C["主分片 P1"]
A --> D["主分片 P2"]
B --> E["副本 R0"]
C --> F["副本 R1"]
D --> G["副本 R2"]
E --> H["节点故障时可提升为主分片"]
F --> H
G --> H集群基本结构
flowchart TD
A["Cluster 集群"] --> B["Master eligible 节点"]
A --> C["Data 节点 1"]
A --> D["Data 节点 2"]
A --> E["Data 节点 3"]
A --> F["Coordinating 节点"]
F --> G["接收搜索请求并合并结果"]
C --> H["保存分片并执行查询"]
D --> H
E --> H
B --> I["管理元数据和分片分配"]一个索引会被拆成多个主分片,每个主分片可以有多个副本分片。主分片和它自己的副本不会分配到同一个节点上,否则节点故障时副本也会一起丢失。
核心概念
| 概念 | 说明 |
|---|---|
| Cluster | ES 集群,由多个节点组成 |
| Node | 一个 ES 实例 |
| Master eligible Node | 有资格成为主节点,管理集群元数据 |
| Data Node | 保存数据和执行查询、聚合 |
| Coordinating Node | 接收请求、分发到分片、合并结果 |
| Index | 逻辑索引,一类文档集合 |
| Primary Shard | 主分片,负责写入 |
| Replica Shard | 副本分片,提高可用性和查询能力 |
| Segment | Lucene 不可变索引文件 |
写入流程
flowchart TD
A["客户端写入文档"] --> B["协调节点接收请求"]
B --> C["根据 _id 或 routing 计算目标分片"]
C --> D["主分片写入"]
D --> E["复制到副本分片"]
E --> F["达到写入确认条件"]
F --> G["返回写入结果"]文档默认根据 _id 路由到某个主分片。主分片写入成功后,再复制到副本分片。
如果商品数据按店铺查询特别多,可以考虑 routing 到店铺维度,但 routing 设计不好会导致热点分片。不要为了“看起来高级”随便加 routing。
查询流程
flowchart TD
A["客户端查询"] --> B["协调节点"]
B --> C["分发到相关分片"]
C --> D["各分片本地查询 TopN"]
D --> E["协调节点合并排序"]
E --> F["执行 fetch 获取文档"]
F --> G["返回结果"]查询会分发到多个分片,协调节点负责合并结果。因此分片过多会增加协调成本。深分页时,每个分片都要返回更多候选结果,协调节点压力会明显升高。
健康状态
| 状态 | 含义 | 常见原因 |
|---|---|---|
| Green | 主分片和副本都正常 | 集群健康 |
| Yellow | 主分片正常,部分副本未分配 | 单节点副本无法分配、节点不足、磁盘水位 |
| Red | 部分主分片不可用 | 数据节点故障、磁盘问题、分片损坏 |
单节点开发环境出现 Yellow 很常见,因为副本不能和主分片放在同一个节点。
分片规划
分片不是越多越好。
过多分片的问题:
- 集群元数据变大。
- 查询协调成本增加。
- 小分片浪费资源。
- 恢复和迁移更慢。
- JVM 堆内存和文件句柄压力更大。
规划时要考虑:
| 问题 | 影响 |
|---|---|
| 数据总量多大 | 决定索引数量和分片大小 |
| 每天增长多少 | 决定是否按天、按月滚动 |
| 查询是按时间还是全量 | 决定索引拆分方式 |
| 写入吞吐多高 | 决定 refresh、bulk、节点配置 |
| 保留多久 | 决定 ILM 生命周期 |
常见建议:
- 商品搜索这类核心索引,分片数量要根据数据量和节点数规划,不要每天滚动。
- 日志索引通常按时间滚动,配合 ILM 管理生命周期。
- 小数据量不要拆太多分片。
- 分片数一旦设置,调整成本较高,要提前评估。
商品搜索和日志索引的区别
| 对比 | 商品搜索 | 日志检索 |
|---|---|---|
| 数据变化 | 商品频繁改价、上下架、更新销量 | 持续追加写入,较少更新 |
| 索引命名 | product_search_v1、product_search_v2 | app-log-2026.07.01 |
| 查询特点 | 关键词、过滤、排序、聚合 | 时间范围、traceId、level、message |
| 生命周期 | 长期保留,重建后切别名 | 按时间保留,过期删除或降级 |
| 优化重点 | 相关性、分词、业务排序 | 写入吞吐、磁盘、ILM |
不要把日志索引的按天滚动模式照搬到商品搜索,也不要把商品搜索的别名重建模式照搬到海量日志。
常用排查命令
GET /_cluster/health
GET /_cat/nodes?v
GET /_cat/indices?v
GET /_cat/shards?v
GET /_cluster/allocation/explain
GET /_nodes/hot_threads排查顺序:
flowchart TD
A["发现集群异常"] --> B["查看 _cluster/health"]
B --> C{"状态"}
C -- "yellow" --> D["查看未分配副本"]
C -- "red" --> E["查看不可用主分片"]
D --> F["检查节点数量、磁盘水位、分片规则"]
E --> F
F --> G["使用 allocation explain 定位原因"]
G --> H["处理磁盘、节点、索引或分配规则"]磁盘水位
ES 会根据磁盘使用率控制分片分配。磁盘水位过高时,分片可能无法分配,甚至索引被设置为只读。
常见处理:
- 清理过期索引。
- 扩容磁盘或增加节点。
- 调整 ILM 策略。
- 检查是否有异常大索引。
- 检查日志是否无限保留。
典型现象:
| 现象 | 可能原因 |
|---|---|
| 新索引无法分配副本 | 磁盘超过水位线 |
| 写入报只读错误 | flood stage 水位触发保护 |
| 集群持续 yellow | 副本没有合适节点可放 |
| 查询和写入都变慢 | 磁盘 IO 压力大 |
写入性能优化
大量初始化数据或重建索引时,常见做法:
- 使用 Bulk 批量写入。
- 适当调大
refresh_interval,导入完成后再恢复。 - 根据业务可用性临时降低副本数,完成后再恢复。
- 控制并发,避免把集群写爆。
- 监控 rejected、CPU、磁盘 IO、GC。
Bulk 示例:
POST /_bulk
{ "index": { "_index": "product_search", "_id": "1001" } }
{ "id": 1001, "productName": "无线蓝牙耳机", "stockStatus": "IN_STOCK" }
{ "index": { "_index": "product_search", "_id": "1002" } }
{ "id": 1002, "productName": "机械键盘", "stockStatus": "IN_STOCK" }Bulk 不是越大越好。过大的批次会增加内存压力和失败重试成本,要结合文档大小和集群能力压测。
查询性能排查
flowchart TD
A["查询慢"] --> B["查看慢日志"]
B --> C["用 profile 分析 DSL"]
C --> D["检查深分页"]
D --> E["检查 wildcard、脚本排序、大聚合"]
E --> F["检查分片数量和分片大小"]
F --> G["检查 CPU、磁盘、GC、线程池拒绝"]常见问题:
| 问题 | 处理 |
|---|---|
| 深分页 | 限制页数,使用 search_after |
| 大聚合 | 缩小时间范围,优化字段类型,控制 bucket 数 |
| 通配符慢 | 改用分词、ngram 或搜索建议 |
| 分片太多 | 合理规划索引,减少小分片 |
| 排序慢 | 确认排序字段类型正确,避免脚本排序 |
常见问题
| 问题 | 可能原因 | 建议 |
|---|---|---|
| 单节点 yellow | 副本无处可放 | 开发环境可把副本设为 0 |
| red | 主分片不可用 | 查节点、磁盘、分片分配 |
| 查询变慢 | 分片多、查询复杂、缓存失效 | 看慢日志和查询 DSL |
| 写入变慢 | refresh 频繁、副本多、磁盘慢 | 调整 refresh、批量写入 |
| 分片未分配 | 磁盘水位、节点不足、规则限制 | allocation explain |
| 重建索引很慢 | bulk 太小或太大、refresh 频繁 | 批量调优,临时调整 refresh |
小结
Elasticsearch 集群学习重点是 Node、Index、Shard、Replica、健康状态、分片规划和排障命令。
生产排障时先看 health,再看 shards 和 allocation explain;查询慢看 slowlog 和 profile;磁盘问题看水位和 ILM。分片规划要克制,过多分片会带来明显管理和查询成本。
