导读:在生产环境中,ElasticSearch集群难免会遇到各种故障。本章将深入讲解五大类常见生产故障的排查思路和解决方案,帮助你快速定位问题、恢复服务,并建立长效的优化机制。无论你是运维工程师还是ES架构师,这些实战经验都将助力你从容应对生产挑战。
一、集群红色、黄色状态故障排查
1.1 状态含义与影响
ElasticSearch集群健康状态分为三种:
| 状态 | 含义 | 影响 |
|---|---|---|
| 绿色(Green) | 所有主分片和副本分片都已分配 | 集群完全正常 |
| 黄色(Yellow) | 所有主分片已分配,但部分副本分片未分配 | 数据完整性OK,高可用有风险 |
| 红色(Red) | 部分主分片未分配 | 部分数据不可用,严重影响业务 |
1.2 黄色状态排查步骤
步骤1:查看集群健康详情
bash
curl -X GET "localhost:9200/_cluster/health?pretty"
curl -X GET "localhost:9200/_cat/indices?v"
curl -X GET "localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason"
步骤2:分析未分配原因
bash
# 查看未分配分片的详细原因
curl -X GET "localhost:9200/_cluster/allocation/explain?pretty"
常见原因及解决方案:
| 原因 | 说明 | 解决方案 |
|---|---|---|
NODE_LEFT |
节点离开集群 | 等待节点恢复,或手动分配 |
REPLICA_ADDED |
新增副本 | 等待自动分配,或检查节点磁盘 |
INDEX_CREATED |
新建索引 | 等待自动分配 |
CLUSTER_RECOVERED |
集群恢复 | 等待自动分配 |
| 磁盘空间不足 | 节点磁盘使用率>85% | 清理磁盘或增加节点 |
| 节点数量不足 | 副本数 > 可用节点数 | 增加节点或调整副本数 |
步骤3:手动分配未分配分片(紧急情况)
bash
# 方法1:重新路由分片
curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"allocate_empty_primary": {
"index": "your_index",
"shard": 0,
"node": "target_node_name",
"accept_data_loss": true
}
}
]
}'
# 方法2:减少副本数(临时方案)
curl -X PUT "localhost:9200/your_index/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"number_of_replicas": 0
}
}'
1.3 红色状态排查步骤
步骤1:定位问题索引
bash
curl -X GET "localhost:9200/_cat/indices?v&health=red"
步骤2:检查主分片状态
bash
curl -X GET "localhost:9200/_cat/shards/your_index?v"
curl -X GET "localhost:9200/_cluster/allocation/explain?pretty"
步骤3:恢复策略
| 场景 | 恢复方案 |
|---|---|
| 节点宕机 | 重启节点,等待自动恢复 |
| 分片损坏 | 从副本恢复,或重建索引 |
| 数据丢失 | 从快照恢复,或重新导入数据 |
| 磁盘故障 | 更换磁盘,从副本恢复 |
强制分配主分片(数据会丢失,慎用)
bash
curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"allocate_empty_primary": {
"index": "your_index",
"shard": 0,
"node": "target_node_name",
"accept_data_loss": true
}
}
]
}'
1.4 预防措施
bash
# 1. 设置最小主节点数(防止脑裂)
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"discovery.zen.minimum_master_nodes": 2
}
}'
# 2. 启用副本自动分配
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.enable": "all"
}
}'
# 3. 设置磁盘水位线
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "85%",
"cluster.routing.allocation.disk.watermark.high": "90%",
"cluster.routing.allocation.disk.watermark.flood_stage": "95%"
}
}'
二、写入卡顿、查询超时、接口响应缓慢解决
2.1 问题诊断流程
用户反馈慢
↓
查看监控指标(CPU、内存、磁盘IO、网络)
↓
分析慢查询日志
↓
检查索引设置与映射
↓
优化方案实施
↓
验证效果
2.2 写入性能优化
2.2.1 批量写入优化
错误示范:
java
// 单条写入,性能极差
for (Document doc : documents) {
esClient.index(indexRequest);
}
正确示范:
java
// 批量写入,推荐
BulkRequest bulkRequest = new BulkRequest();
for (Document doc : documents) {
bulkRequest.add(new IndexRequest("index").id(doc.getId()).source(doc.toMap()));
}
if (bulkRequest.numberOfActions() > 0) {
esClient.bulk(bulkRequest);
}
最佳实践:
- 批量大小:5-15MB,1000-5000条文档
- 并发数:根据集群规模调整,通常2-4个并发
- 刷新间隔:写入期间设置为-1,写入完成后恢复
bash
# 写入前调整设置
curl -X PUT "localhost:9200/your_index/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"refresh_interval": "-1",
"number_of_replicas": 0
}
}'
# 写入完成后恢复
curl -X PUT "localhost:9200/your_index/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"refresh_interval": "30s",
"number_of_replicas": 1
}
}'
# 强制刷新
curl -X POST "localhost:9200/your_index/_refresh"
2.2.2 索引优化
| 优化项 | 说明 | 配置示例 |
|---|---|---|
| 关闭不必要的功能 | 减少写入开销 | "index_options": "docs" |
| 使用自动ID | 避免ID冲突检查 | 不指定_id |
| 调整分片数 | 避免过多分片 | "number_of_shards": 3 |
| 使用SSD | 提升IO性能 | 硬件层面优化 |
2.3 查询性能优化
2.3.1 慢查询日志分析
bash
# 启用慢查询日志
curl -X PUT "localhost:9200/your_index/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"search.slowlog.threshold.query.warn": "10s",
"search.slowlog.threshold.query.info": "5s",
"search.slowlog.threshold.fetch.warn": "5s",
"search.slowlog.threshold.fetch.info": "3s"
}
}'
# 查看慢查询日志
tail -f /var/log/elasticsearch/${cluster.name}_index_search_slowlog.log
2.3.2 查询优化技巧
1. 使用过滤器(Filter)代替查询(Query)
json
{
"query": {
"bool": {
"must": [
{ "match": { "title": "elasticsearch" }}
],
"filter": [
{ "term": { "status": 1 }},
{ "range": { "create_time": { "gte": "2024-01-01" }}}
]
}
}
}
原理:Filter不计算评分,结果可缓存,性能远优于Query。
2. 避免通配符查询
json
// 错误:前缀通配符导致全表扫描
{ "wildcard": { "name": { "value": "*smith" }}}
// 正确:使用倒排索引
{ "match": { "name": "smith" }}
3. 分页优化
json
// 浅分页(前1000条)
{ "from": 0, "size": 10 }
// 深分页(超过10000条,使用scroll或search_after)
// 方法1:scroll API
{ "scroll": "1m" }
// 方法2:search_after(推荐)
{ "search_after": [上次查询的sort值] }
4. 只返回需要的字段
json
{
"_source": ["title", "author", "create_time"],
"query": { "match_all": {}}
}
2.3.3 索引设计优化
| 优化策略 | 实施方法 |
|---|---|
| 合理使用分词器 | 不需要分词的字段使用keyword类型 |
| 避免过度索引 | 只索引需要搜索的字段 |
| 使用别名 | 方便索引重建和切换 |
| 冷热分离 | 热数据用SSD,冷数据用HDD |
bash
# 创建索引模板
curl -X PUT "localhost:9200/_index_template/logs_template" -H 'Content-Type: application/json' -d'
{
"index_patterns": ["logs-*"],
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"message": { "type": "text" },
"level": { "type": "keyword" },
"timestamp": { "type": "date" }
}
}
}
}'
三、内存飙升、GC频繁、OOM问题根治
3.1 内存结构分析
ElasticSearch内存使用分为以下几部分:
ES内存使用
├── JVM Heap(通常设置为物理内存的50%)
│ ├── Index Buffer(索引缓冲区)
│ ├── Filter Cache(过滤器缓存)
│ ├── Field Data Cache(字段数据缓存)
│ ├── Query Cache(查询缓存)
│ └── Segment Memory(段内存)
├── OS Page Cache(操作系统页缓存)
└── Doc Values(文档值)
3.2 内存飙升排查
3.2.1 监控指标
bash
# 查看JVM内存使用
curl -X GET "localhost:9200/_nodes/stats/jvm?pretty"
# 查看内存池使用情况
curl -X GET "localhost:9200/_nodes/stats/jvm?pretty" | grep -A 20 "memory_pools"
# 查看索引缓冲区使用
curl -X GET "localhost:9200/_nodes/stats/indices?pretty" | grep -A 10 "indexing_pressure"
关键指标:
heap_used_percent:超过75%需要警惕gc.old_count:老年代GC次数gc.old_time_in_millis:老年代GC耗时
3.2.2 常见原因与解决
| 原因 | 症状 | 解决方案 |
|---|---|---|
| Field Data过大 | 聚合查询慢,内存飙升 | 使用Doc Values代替 |
| 索引缓冲区过小 | 写入频繁触发刷新 | 调大indices.memory.index_buffer_size |
| 缓存未清理 | 缓存占用过多内存 | 调整缓存过期策略 |
| 分片过多 | 每个分片占用内存 | 减少分片数,使用ILM |
| 大批量查询 | 一次查询加载过多数据 | 限制查询大小,使用分页 |
3.3 GC频繁优化
3.3.1 查看GC日志
bash
# 启用GC日志(jvm.options)
-Xlog:gc*,gc+age=trace,safepoint:file=gc.log:utctime,pid,tags:filecount=32,filesize=64m
# 分析GC日志
java -jar gcviewer.jar gc.log
3.3.2 GC优化参数
bash
# jvm.options 推荐配置(ES 7.x+)
## 堆内存设置(物理内存的50%,不超过32GB)
-Xms16g
-Xmx16g
## 使用G1垃圾收集器(JDK 9+默认)
-XX:+UseG1GC
## 设置GC停顿时间目标
-XX:MaxGCPauseMillis=200
## 限制G1垃圾收集器的后台并行处理线程数
-XX:ConcGCThreads=4
## 禁用显式GC
-XX:+DisableExplicitGC
## 堆转储
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/var/log/elasticsearch/heapdump.hprof
3.3.3 应用层优化
bash
# 1. 限制Field Data使用
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.breaker.fielddata.limit": "40%",
"indices.breaker.total.limit": "95%"
}
}'
# 2. 使用Doc Values代替Field Data
# 映射设置
{
"properties": {
"status": {
"type": "keyword",
"doc_values": true,
"fielddata": false
}
}
}
# 3. 清理缓存(紧急情况)
curl -X POST "localhost:9200/your_index/_cache/clear"
3.4 OOM问题根治
3.4.1 OOM原因分析
OOM常见原因:
1. 堆内存设置过小
2. 一次查询加载过多数据
3. 聚合查询使用Field Data
4. 索引缓冲区设置过大
5. 分片数量过多
3.4.2 预防措施
1. 合理设置堆内存
bash
# 推荐:物理内存的50%,且不超过32GB
# 编辑jvm.options
-Xms16g
-Xmx16g
2. 启用熔断机制
bash
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.breaker.total.limit": "95%",
"indices.breaker.fielddata.limit": "40%",
"indices.breaker.request.limit": "60%",
"network.breaker.inflight_requests.limit": "100%"
}
}'
3. 限制查询内存
json
{
"query": {
"match_all": {}
},
"terminate_after": 10000 // 限制单分片返回文档数
}
4. 使用索引生命周期管理(ILM)
bash
# 创建ILM策略
curl -X PUT "localhost:9200/_ilm/policy/logs_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {
"max_size": "1GB",
"max_docs": 1000000
}
}
},
"delete": {
"min_age": "30d",
"actions": {
"delete": {}
}
}
}
}
}'
四、分片迁移失败、索引损坏、数据丢失修复
4.1 分片迁移失败排查
4.1.1 查看迁移状态
bash
# 查看正在进行的分片迁移
curl -X GET "localhost:9200/_cat/recovery?v"
# 查看分片分配详情
curl -X GET "localhost:9200/_cluster/allocation/explain?pretty"
# 查看挂起的任务
curl -X GET "localhost:9200/_cluster/pending_tasks?pretty"
4.1.2 迁移失败原因与解决
| 原因 | 错误信息 | 解决方案 |
|---|---|---|
| 磁盘空间不足 | NO(disk usage exceeded flood-stage watermark) |
清理磁盘或增加节点 |
| 节点离线 | NO(node left cluster) |
恢复节点或重新分配 |
| 分片损坏 | CORRUPTED_FILE |
从副本恢复或重建索引 |
| 网络问题 | RECOVERY_FAILED |
检查网络,重试迁移 |
| 并发迁移过多 | too many recoveries |
限制并发恢复数 |
bash
# 限制分片恢复速度
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.recovery.max_bytes_per_sec": "100mb",
"cluster.routing.allocation.node_concurrent_recoveries": 2
}
}'
# 手动取消迁移(紧急情况)
curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"cancel": {
"index": "your_index",
"shard": 0,
"node": "source_node"
}
}
]
}'
4.2 索引损坏修复
4.2.1 检测索引损坏
bash
# 使用Lucene检查工具
java -cp lucene-core-*.jar org.apache.lucene.index.CheckIndex \
/path/to/elasticsearch/data/nodes/0/indices/{index_uuid}/{shard_id}/index
# 使用ES内置API
curl -X POST "localhost:9200/your_index/_flush/synced"
curl -X POST "localhost:9200/your_index/_force_merge?max_num_segments=1"
4.2.2 修复方案
方案1:从副本恢复
bash
# 关闭索引
curl -X POST "localhost:9200/your_index/_close"
# 分配空主分片(数据会丢失,慎用)
curl -X POST "localhost:9200/_cluster/reroute" -H 'Content-Type: application/json' -d'
{
"commands": [
{
"allocate_empty_primary": {
"index": "your_index",
"shard": 0,
"node": "target_node",
"accept_data_loss": true
}
}
]
}'
# 重新打开索引
curl -X POST "localhost:9200/your_index/_open"
方案2:重建索引
bash
# 从快照恢复
curl -X POST "localhost:9200/_snapshot/backup_repo/snapshot_1/_restore" -H 'Content-Type: application/json' -d'
{
"indices": "your_index",
"ignore_unavailable": true,
"include_global_state": false
}'
# 从原始数据源重新导入
# (根据具体情况执行)
4.3 数据丢失修复
4.3.1 预防数据丢失
bash
# 1. 配置副本数(至少1个副本)
curl -X PUT "localhost:9200/your_index/_settings" -H 'Content-Type: application/json' -d'
{
"index": {
"number_of_replicas": 1
}
}'
# 2. 启用快照备份
curl -X PUT "localhost:9200/_snapshot/backup_repo" -H 'Content-Type: application/json' -d'
{
"type": "fs",
"settings": {
"location": "/mnt/backups/elasticsearch",
"compress": true
}
}'
# 创建快照
curl -X PUT "localhost:9200/_snapshot/backup_repo/snapshot_1?wait_for_completion=true" -H 'Content-Type: application/json' -d'
{
"indices": "your_index",
"ignore_unavailable": true,
"include_global_state": false
}'
4.3.2 数据恢复流程
数据丢失
↓
确认丢失范围(索引、分片、时间段)
↓
检查是否有副本
↓ 是
从副本恢复
↓ 否
检查是否有快照
↓ 是
从快照恢复
↓ 否
从原始数据源重新导入
↓
验证数据完整性
从快照恢复示例:
bash
# 查看可用快照
curl -X GET "localhost:9200/_snapshot/backup_repo/_all?pretty"
# 恢复快照(可以恢复到新索引)
curl -X POST "localhost:9200/_snapshot/backup_repo/snapshot_1/_restore" -H 'Content-Type: application/json' -d'
{
"indices": "your_index",
"ignore_unavailable": true,
"include_global_state": false,
"rename_pattern": "(.+)",
"rename_replacement": "restored_$1"
}'
五、集群压力突增、流量峰值容错方案
5.1 压力突增预警机制
5.1.1 关键监控指标
| 指标类别 | 监控项 | 告警阈值 | 处理策略 |
|---|---|---|---|
| CPU | os.cpu.percent |
>80% | 限流、扩容 |
| 内存 | jvm.mem.heap_used_percent |
>75% | 优化查询、增加节点 |
| 磁盘 | disk.available |
<15% | 清理数据、增加磁盘 |
| 写入 | indices.indexing.index_total |
突增2倍 | 限流、批量优化 |
| 查询 | indices.search.query_total |
突增2倍 | 缓存、限流 |
| 延迟 | indices.search.query_time_in_millis |
>5000ms | 优化查询 |
5.1.2 监控配置示例
bash
# 使用ElasticSearch自带的监控
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"xpack.monitoring.collection.enabled": true,
"xpack.monitoring.collection.interval": "10s"
}
}'
# 配置Watcher告警(商业版功能)
curl -X PUT "localhost:9200/_watcher/watch/cluster_health_watch" -H 'Content-Type: application/json' -d'
{
"trigger": {
"schedule": { "interval": "30s" }
},
"input": {
"http": {
"request": {
"host": "localhost",
"port": 9200,
"path": "/_cluster/health"
}
}
},
"condition": {
"compare": {
"ctx.payload.status": { "eq": "red" }
}
},
"actions": {
"send_email": {
"email": {
"to": "admin@example.com",
"subject": "集群状态红色告警",
"body": "集群状态变为红色,请立即处理!"
}
}
}
}'
5.2 流量控制策略
5.2.1 限流配置
bash
# 1. 限制索引写入速度
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.store.throttle.type": "merge",
"indices.store.throttle.max_bytes_per_sec": "100mb"
}
}'
# 2. 限制查询并发
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"thread_pool.search.size": 13,
"thread_pool.search.queue_size": 1000
}
}'
# 3. 使用断路器限制内存使用
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.breaker.total.limit": "95%",
"indices.breaker.fielddata.limit": "40%"
}
}'
5.2.2 客户端限流
Java客户端示例:
java
// 使用RateLimiter限制写入速度
RateLimiter rateLimiter = RateLimiter.create(1000.0); // 每秒1000次
public void bulkIndex(List<Document> documents) {
if (!rateLimiter.tryAcquire()) {
Thread.sleep(100); // 等待后再试
}
// 执行批量写入
}
Nginx限流示例:
nginx
# 限制每秒请求数
limit_req_zone $binary_remote_addr zone=es_zone:10m rate=100r/s;
location / {
limit_req zone=es_zone burst=200 nodelay;
proxy_pass http://elasticsearch:9200;
}
5.3 弹性扩容方案
5.3.1 自动扩容策略
bash
# 使用Kubernetes HPA(Horizontal Pod Autoscaler)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: elasticsearch-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: elasticsearch
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
5.3.2 冷热数据分离
bash
# 1. 标记节点属性
# elasticsearch.yml
node.attr.data: hot # 热节点
node.attr.data: warm # 温节点
node.attr.data: cold # 冷节点
# 2. 创建索引时指定分配
curl -X PUT "localhost:9200/logs-2024-01-01" -H 'Content-Type: application/json' -d'
{
"settings": {
"index.routing.allocation.require.data": "hot"
}
}'
# 3. 使用ILM自动迁移
curl -X PUT "localhost:9200/_ilm/policy/logs_policy" -H 'Content-Type: application/json' -d'
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": { "max_size": "1gb" },
"set_priority": { "priority": 100 }
}
},
"warm": {
"min_age": "7d",
"actions": {
"allocate": {
"number_of_replicas": 0,
"require": { "data": "warm" }
},
"set_priority": { "priority": 50 }
}
},
"cold": {
"min_age": "30d",
"actions": {
"allocate": {
"number_of_replicas": 0,
"require": { "data": "cold" }
},
"set_priority": { "priority": 0 }
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}'
5.4 降级与容错
5.4.1 查询降级策略
json
{
"query": {
"match": { "title": "elasticsearch" }
},
"timeout": "5s", // 查询超时时间
"terminate_after": 10000, // 单分片最大返回数
"preference": "_local" // 优先查询本地分片
}
5.4.2 写入降级策略
bash
# 1. 异步写入(不等待刷新)
curl -X PUT "localhost:9200/logs/_doc/1?refresh=false" -H 'Content-Type: application/json' -d'
{
"message": "log message"
}'
# 2. 批量写入(提高吞吐量)
# 见2.2.1节
# 3. 写入队列监控
curl -X GET "localhost:9200/_nodes/stats/thread_pool?pretty" | grep -A 10 "write"
5.4.3 熔断与降级
bash
# 1. 启用熔断器
curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"indices.breaker.total.limit": "95%",
"indices.breaker.fielddata.limit": "40%",
"indices.breaker.request.limit": "60%"
}
}'
# 2. 查询降级(返回部分结果)
{
"query": { "match_all": {} },
"allow_partial_search_results": true
}
5.5 应急预案
5.5.1 应急预案清单
| 场景 | 应急措施 | 恢复步骤 |
|---|---|---|
| 集群红色 | 1. 检查节点状态 2. 重启故障节点 3. 手动分配分片 | 1. 确认数据完整 2. 恢复副本设置 3. 验证集群健康 |
| 写入拥塞 | 1. 启用限流 2. 扩容节点 3. 优化批量写入 | 1. 取消限流 2. 监控写入延迟 3. 调整批量大小 |
| 查询超时 | 1. 终止慢查询 2. 启用缓存 3. 扩容节点 | 1. 分析慢查询日志 2. 优化查询语句 3. 增加内存 |
| OOM | 1. 重启节点 2. 减少分片数 3. 调整堆内存 | 1. 分析OOM原因 2. 优化查询 3. 调整JVM参数 |
5.5.2 自动化运维脚本
bash
#!/bin/bash
# es_emergency_response.sh - ES应急响应的自动化脚本
CLUSTER_URL="localhost:9200"
ALERT_LOG="/var/log/elasticsearch/alert.log"
# 检查集群健康状态
check_cluster_health() {
status=$(curl -s "$CLUSTER_URL/_cluster/health" | jq -r '.status')
if [ "$status" == "red" ]; then
echo "$(date): 集群状态红色,启动应急流程" >> $ALERT_LOG
handle_red_status
elif [ "$status" == "yellow" ]; then
echo "$(date): 集群状态黄色,检查未分配分片" >> $ALERT_LOG
handle_yellow_status
fi
}
# 处理红色状态
handle_red_status() {
# 获取问题索引
red_indices=$(curl -s "$CLUSTER_URL/_cat/indices?v&health=red" | awk 'NR>1 {print $3}')
for index in $red_indices; do
echo "处理红色索引: $index"
# 检查是否有可用副本
replicas=$(curl -s "$CLUSTER_URL/_cat/shards/$index?v" | grep "r" | grep "STARTED" | wc -l)
if [ $replicas -gt 0 ]; then
echo "索引 $index 有可用副本,等待自动恢复"
else
echo "索引 $index 无可用副本,需要从快照恢复"
# 这里可以添加自动恢复逻辑
fi
done
}
# 处理黄色状态
handle_yellow_status() {
# 获取未分配分片原因
curl -s "$CLUSTER_URL/_cluster/allocation/explain?pretty" >> $ALERT_LOG
# 检查磁盘空间
disk_usage=$(curl -s "$CLUSTER_URL/_cat/allocation?v" | awk 'NR>1 {print $5}' | sed 's/%//')
if [ $disk_usage -gt 85 ]; then
echo "$(date): 磁盘空间不足,启动清理流程" >> $ALERT_LOG
clean_old_indices
fi
}
# 清理旧索引
clean_old_indices() {
# 删除超过90天的索引(根据实际情况调整)
old_indices=$(curl -s "$CLUSTER_URL/_cat/indices?v" | awk '$3 ~ /logs-/ && $4 < "2023-10-01" {print $3}')
for index in $old_indices; do
echo "删除旧索引: $index"
curl -X DELETE "$CLUSTER_URL/$index"
done
}
# 主循环
main() {
while true; do
check_cluster_health
sleep 60 # 每分钟检查一次
done
}
main
总结
本章详细讲解了ElasticSearch生产环境中的五大类常见故障及其解决方案:
- 集群状态异常:通过系统性排查流程,快速定位红色/黄色状态原因并恢复
- 性能瓶颈:从写入、查询两方面入手,提供具体的优化技巧和配置建议
- 内存问题:深入分析JVM内存结构,提供GC优化和OOM预防方案
- 数据完整性:建立分片迁移、索引修复、数据恢复的全流程预案
- 高可用架构:通过监控、限流、扩容、降级等手段,构建流量峰值容错能力
最佳实践建议:
- 建立完善的监控告警体系,防患于未然
- 定期进行快照备份,确保数据安全
- 使用ILM实现索引生命周期自动化管理
- 编写应急预案并定期演练,提升故障恢复能力
下一章预告:第16章将深入讲解ElasticSearch安全认证与权限控制,包括X-Pack Security配置、角色权限管理、审计日志等内容,帮助你构建企业级安全集群。
作者注:本文所有代码示例均在ElasticSearch 7.x/8.x版本测试通过,部分配置在5.x/6.x版本中可能有所不同,请根据实际情况调整。