上篇介绍了 CPU、内存、磁盘等基础设施监控,本篇深入索引层面——线程池、分片分布、查询性能、段合并,帮你快速定位性能瓶颈。

为什么要监控索引性能指标?

基础设施健康不代表业务正常,索引层面的问题往往更隐蔽:

  • 线程池队列堆积 → 请求被拒绝,用户报错
  • 分片分布不均 → 热点节点,负载倾斜
  • 查询性能下降 → 响应变慢,用户投诉
  • 段合并频繁 → 写入吞吐量下降

这些问题在 CPU、内存指标上可能看不出来,需要专门的索引监控。

线程池监控:发现队列堆积

线程池是 Easysearch 处理请求的核心,队列堆积或拒绝是性能问题的早期信号:

1
GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected,type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
node_name name                   active queue rejected type
node-1 ai 0 0 0 scaling
node-1 analyze 0 0 0 fixed
node-1 async_search_generic 0 0 0 scaling
node-1 fetch_shard_started 0 0 0 scaling
node-1 fetch_shard_store 0 0 0 scaling
node-1 flush 0 0 0 scaling
node-1 force_merge 0 0 0 fixed
node-1 generic 0 0 0 scaling
node-1 get 0 0 0 fixed
node-1 job_scheduler 0 0 0 fixed
node-1 listener 0 0 0 fixed
node-1 management 1 0 0 scaling
node-1 refresh 0 0 0 scaling
node-1 replication_follower 0 0 0 scaling
node-1 replication_leader 0 0 0 fixed
node-1 search 0 0 0 fixed_auto_queue_size
node-1 search_throttled 0 0 0 fixed_auto_queue_size
node-1 snapshot 0 0 0 scaling
node-1 sql-worker 0 0 0 fixed
node-1 system_read 0 0 0 fixed
node-1 system_write 0 0 0 fixed
node-1 warmer 0 0 0 scaling
node-1 write 0 0 0 fixed

重点关注这几个线程池:

线程池作用告警建议
search处理搜索请求queue 持续增长 或 rejected > 0
write处理写入请求queue 持续增长 或 rejected > 0
get处理 GET 请求rejected > 0
force_merge段合并操作active 长时间 > 0 需关注

💡 关于告警阈值:建议先观察集群正常运行时的基线,再根据实际情况设置告警。关键是关注 rejected > 0(请求被拒绝)和 queue 持续增长(处理能力跟不上)。

查看线程池配置:

1
2
# 查看默认配置
GET _cluster/settings?include_defaults=true&filter_path=defaults.thread_pool
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
{
"defaults": {
"thread_pool": {
"search": {
"max_queue_size": "1000",
"queue_size": "1000",
"size": "16",
"auto_queue_frame_size": "2000",
"target_response_time": "1s",
"min_queue_size": "1000"
},
"write": {
"queue_size": "10000",
"size": "10"
},
"get": {
"queue_size": "1000",
"size": "10"
},
"analyze": {
"queue_size": "256",
"size": "8"
},
"management": {
"core": "1",
"max": "5",
"keep_alive": "5m"
},
"flush": {
"core": "1",
"max": "5",
"keep_alive": "5m"
},
"force_merge": {
"queue_size": "-1",
"size": "1"
}
}
}
}
1
2
# 查看节点实际配置
GET _nodes/thread_pool
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
44
45
46
47
48
{
"nodes": {
"J4TFDrHMSoq-MwQp-2LGlA": {
"name": "node-1",
"thread_pool": {
"search": {
"type": "fixed_auto_queue_size",
"size": 16,
"queue_size": 1000
},
"write": {
"type": "fixed",
"size": 10,
"queue_size": 10000
},
"get": {
"type": "fixed",
"size": 10,
"queue_size": 1000
},
"analyze": {
"type": "fixed",
"size": 8,
"queue_size": 256
},
"sql-worker": {
"type": "fixed",
"size": 10,
"queue_size": 1000
},
"ai": {
"type": "scaling",
"core": 0,
"max": 10,
"keep_alive": "10m",
"queue_size": -1
},
"management": {
"type": "scaling",
"core": 1,
"max": 5,
"keep_alive": "5m",
"queue_size": -1
}
}
}
}
}

💡 两个 API 的区别:_cluster/settings 返回集群级别的默认配置,_nodes/thread_pool 返回每个节点的实际运行配置(包含 type 信息)。

Easysearch 主要线程池默认配置:

线程池类型sizequeue_size说明
searchfixed_auto_queue_size161000处理搜索请求
writefixed1010000处理写入请求
getfixed101000处理 GET 请求
analyzefixed8256文本分析
managementscaling1-5-1集群管理任务
flushscaling1-5-1刷新到磁盘
refreshscaling1-5-1刷新索引
force_mergefixed1-1段合并
snapshotscaling1-5-1快照操作
sql-workerfixed101000SQL 查询
aiscaling0-10-1AI 功能

💡 queue_size = -1 表示无界队列(scaling 类型线程池的特点)。size 列中 1-5 表示 scaling 类型的 core 到 max 范围。

当前集群解读:

线程池activequeuerejected状态
search000✅ 空闲
write000✅ 空闲
management100✅ 正常
其他000✅ 空闲

所有线程池都很健康,没有队列堆积,没有请求被拒绝。说明当前负载很轻,集群处理能力充足。

⚠️ rejected 不为 0 说明请求被拒绝了,这是严重问题,需要立即排查是资源不足还是请求量过大。

索引级别监控:定位问题索引

集群整体健康不代表每个索引都正常,单独检查索引状态很有必要:

1
2
3
4
5
6
# 查看所有索引,手动筛选异常状态
GET _cat/indices?v&h=index,health,pri,rep,docs.count,store.size

# 或者分别查询
GET _cat/indices?v&health=yellow
GET _cat/indices?v&health=red
1
2
3
4
5
6
health status index                                  uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green open .security CrALo0yxS7SCrgpt-uYnNQ 1 0 8 0 43.8kb 43.8kb
green open .analysis_ik NlUd-mTkTiSZ82ebDwvBJQ 1 0 0 0 208b 208b
yellow open .job-scheduler-lock pjptvYgITByvGHDkOKI2Ng 1 1 1 0 11.7kb 11.7kb
yellow open test-load hSNZa7tqQWuspCOoBae42w 1 1 110 0 19.6kb 19.6kb
yellow open products EmnVyqz4RO69UDcOfECmCQ 1 1 6 0 41.1kb 41.1kb

上面的结果显示有多个 yellow 状态的索引,原因是它们配置了 1 个副本(rep=1),但当前是单节点集群,副本无法分配到其他节点。系统索引(以 . 开头)如 .security.analysis_ik 配置为 0 副本,所以是 green 状态。

1
2
# 按大小排序,找出最大的索引
GET _cat/indices?v&s=store.size:desc&h=index,health,pri,rep,docs.count,store.size

💡 示例输出(生产环境可能看到类似这样的大索引):

1
2
3
4
index                  health pri rep docs.count store.size
logs-2024.01 green 5 0 52340912 28.5gb
metrics-2024.01 green 3 0 18234567 12.3gb
user-behavior green 1 0 2345678 1.2gb

索引健康检查清单:

检查项命令说明
异常状态索引_cat/indices?v&health=yellow应该为空
超大索引_cat/indices?s=store.size:desc单个索引建议 < 50GB
文档数异常_cat/indices?s=docs.count:desc对比历史数据

分片分布监控:避免热点节点

分片分布不均会导致某些节点负载过高:

1
GET _cat/shards?v&s=store:desc&h=index,shard,prirep,state,docs,store,node

💡 示例输出(生产环境可能看到类似这样的分片分布):

1
2
3
4
5
index            shard prirep state   docs   store node
logs-2024.01 0 p STARTED 10468182 5.7gb node-1
logs-2024.01 1 p STARTED 10456823 5.6gb node-1
logs-2024.01 2 p STARTED 10478234 5.8gb node-1
metrics-2024.01 0 p STARTED 6078189 4.1gb node-1
1
2
# 查看每个节点的分片数量
GET _cat/allocation?v
1
2
3
shards disk.indices disk.used disk.avail disk.total disk.percent host          ip            node
7 246.3kb 16gb 228.1gb 244.1gb 6 192.168.215.2 192.168.215.2 node-1
5 UNASSIGNED

💡 关于 UNASSIGNED 分片:上面显示有 5 个未分配的分片,这是因为 test-loadproducts 以及 ILM 相关索引配置了 1 个副本,但当前是单节点集群,副本无法分配到其他节点。这在单节点测试环境是正常的。

分片分布健康指标:

指标健康标准
节点间分片数差异< 20%
单节点最大分片数< 1000
UNASSIGNED 分片应为 0

💡 小贴士:如果发现分片分布不均,可以用 POST _cluster/reroute 手动调整,或调整 cluster.routing.allocation 相关配置。

查询性能监控:定位慢查询

搜索变慢是最常见的用户投诉,这些指标帮你快速定位:

1
GET _nodes/stats/indices/search
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"indices": {
"search": {
"open_contexts": 0,
"query_total": 395,
"query_time_in_millis": 376,
"query_current": 0,
"fetch_total": 387,
"fetch_time_in_millis": 86,
"fetch_current": 0,
"scroll_total": 9,
"scroll_time_in_millis": 708581,
"scroll_current": 0,
"suggest_total": 0,
"suggest_time_in_millis": 0,
"suggest_current": 0,
"point_in_time_total": 0,
"point_in_time_time_in_millis": 0,
"point_in_time_current": 0
}
}
}

关键性能指标计算:

1
2
3
4
5
6
7
平均查询耗时 = query_time_in_millis / query_total
= 376 / 395
= 0.95ms ✅ 健康

平均 fetch 耗时 = fetch_time_in_millis / fetch_total
= 86 / 387
= 0.22ms ✅ 健康
指标计算方式健康阈值
平均查询耗时query_time / query_total< 100ms
平均 fetch 耗时fetch_time / fetch_total< 50ms
当前查询数query_current持续 > 10 需关注
scroll 上下文scroll_current持续增长需关注

当前集群解读:

指标当前值状态
总查询次数395 次-
平均查询耗时0.95ms✅ 非常快
平均 fetch 耗时0.22ms✅ 非常快
当前进行中查询0✅ 无积压
scroll 上下文0✅ 无泄漏
scroll 总耗时708s⚠️ 历史 scroll 查询较多

查询性能非常优秀,平均响应时间在毫秒级,远低于 100ms 的健康阈值。scroll_time 较高是因为之前执行过多次 scroll 查询测试。

⚠️ 如果平均查询耗时突然上升,检查:1) 是否有复杂聚合查询 2) 是否在做段合并 3) 堆内存是否不足

段合并监控:写入性能的隐形杀手

段(Segment)合并是 Lucene 的核心机制,但频繁合并会严重影响写入性能:

1
GET _nodes/stats/indices/merges
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"indices": {
"merges": {
"current": 0,
"current_docs": 0,
"current_size_in_bytes": 0,
"total": 3,
"total_time_in_millis": 49,
"total_docs": 18,
"total_size_in_bytes": 26572,
"total_stopped_time_in_millis": 0,
"total_throttled_time_in_millis": 0,
"total_auto_throttle_in_bytes": 482344960
}
}
}

段合并健康指标:

指标说明关注点
current当前正在进行的合并数持续 > 0 说明合并压力大
total_throttled_time被限流的时间> 0 说明磁盘 I/O 跟不上
total_stopped_time被停止的时间> 0 需要排查原因

当前集群解读:

指标当前值状态
当前合并数0✅ 无合并进行中
历史合并次数3 次✅ 正常
合并总耗时49ms✅ 合并开销很小
合并文档数18 个✅ 小规模合并
被限流时间0✅ I/O 无压力
被停止时间0✅ 正常

段合并状态健康,当前集群数据量较小(135 个文档),已完成 3 次小规模段合并,总耗时仅 49ms。

1
2
# 查看每个索引的段数量
GET _cat/segments?v&h=index,shard,segment,docs.count,size,committed

💡 优化建议

  • 如果段合并频繁,考虑增大 index.refresh_interval(默认 1s)
  • 批量写入时可以临时设置 refresh_interval: -1
  • 单个分片的段数量建议控制在 50 个以内

监控告警建议

根据实践经验,建议设置以下告警阈值:

指标⚠️ 警告🔴 严重
search 线程池 queue持续增长rejected > 0
write 线程池 queue持续增长rejected > 0
线程池 rejected> 0持续 > 0
平均查询耗时> 100ms> 500ms
当前合并数持续 > 2持续 > 5
索引状态yellowred

常用命令速查表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 🧵 线程池状态
GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected

# 📁 索引大小排序
GET _cat/indices?v&s=store.size:desc

# ⚠️ 问题索引(需分别查询 yellow 和 red)
GET _cat/indices?v&health=yellow
GET _cat/indices?v&health=red

# 📦 分片分布
GET _cat/shards?v&s=store:desc

# 💾 磁盘分配详情
GET _cat/allocation?v

# 🔍 查询性能统计
GET _nodes/stats/indices/search

# 🔄 段合并状态
GET _nodes/stats/indices/merges

使用 MCP 工具自动化监控

如果你使用 AI Agent(如 Kiro、Claude Desktop),可以通过 Easysearch MCP Server 让 AI 直接操作集群,实现自然语言监控:

配置 MCP 客户端 (.kiro/settings/mcp.json):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"mcpServers": {
"easysearch": {
"command": "python3",
"args": ["-m", "easysearch_mcp.server"],
"cwd": "/path/to/easysearch-mcp-server/src",
"env": {
"EASYSEARCH_URL": "https://localhost:9200",
"EASYSEARCH_USER": "admin",
"EASYSEARCH_PASSWORD": "your-password",
"PYTHONPATH": "/path/to/easysearch-mcp-server/src"
}
}
}
}

自然语言监控示例:

你说AI 调用的 MCP 工具
“查看线程池状态”cat_thread_pool()
“哪些索引是 yellow 状态”cat_indices(health="yellow")
“查看分片分布”cat_shards()
“查询性能怎么样”nodes_stats(metric="indices")
“有没有段合并在进行”nodes_stats(metric="indices")
“磁盘使用情况”cat_allocation()

MCP Server 提供 121 个工具,覆盖集群管理、索引操作、搜索查询、监控诊断等全部功能,让 AI 成为你的 Easysearch 运维助手。

总结

监控 Easysearch 集群的索引性能,掌握这几个核心 API 就够了:

  • _cat/thread_pool - 线程池队列
  • _cat/indices - 索引健康
  • _cat/shards - 分片分布
  • _nodes/stats/indices/search - 查询性能
  • _nodes/stats/indices/merges - 段合并状态

结合上篇的基础设施监控,你就拥有了完整的 Easysearch 集群监控体系。

Easysearch 完全兼容 Elasticsearch/OpenSearch API,如果你之前用过这些产品,可以无缝迁移。


参考文档: