上篇介绍了 CPU、内存、磁盘等基础设施监控,本篇深入索引层面------线程池、分片分布、查询性能、段合并,帮你快速定位性能瓶颈。
为什么要监控索引性能指标?
基础设施健康不代表业务正常,索引层面的问题往往更隐蔽:
- 线程池队列堆积 → 请求被拒绝,用户报错
- 分片分布不均 → 热点节点,负载倾斜
- 查询性能下降 → 响应变慢,用户投诉
- 段合并频繁 → 写入吞吐量下降
这些问题在 CPU、内存指标上可能看不出来,需要专门的索引监控。
线程池监控:发现队列堆积
线程池是 Easysearch 处理请求的核心,队列堆积或拒绝是性能问题的早期信号:
bash
GET _cat/thread_pool?v&h=node_name,name,active,queue,rejected,type
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 持续增长(处理能力跟不上)。
查看线程池配置:
bash
# 查看默认配置
GET _cluster/settings?include_defaults=true&filter_path=defaults.thread_pool
json
{
"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"
}
}
}
}
bash
# 查看节点实际配置
GET _nodes/thread_pool
json
{
"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 主要线程池默认配置:
| 线程池 | 类型 | size | queue_size | 说明 |
|---|---|---|---|---|
| search | fixed_auto_queue_size | 16 | 1000 | 处理搜索请求 |
| write | fixed | 10 | 10000 | 处理写入请求 |
| get | fixed | 10 | 1000 | 处理 GET 请求 |
| analyze | fixed | 8 | 256 | 文本分析 |
| management | scaling | 1-5 | -1 | 集群管理任务 |
| flush | scaling | 1-5 | -1 | 刷新到磁盘 |
| refresh | scaling | 1-5 | -1 | 刷新索引 |
| force_merge | fixed | 1 | -1 | 段合并 |
| snapshot | scaling | 1-5 | -1 | 快照操作 |
| sql-worker | fixed | 10 | 1000 | SQL 查询 |
| ai | scaling | 0-10 | -1 | AI 功能 |
💡
queue_size = -1表示无界队列(scaling 类型线程池的特点)。size列中1-5表示 scaling 类型的 core 到 max 范围。
当前集群解读:
| 线程池 | active | queue | rejected | 状态 |
|---|---|---|---|---|
| search | 0 | 0 | 0 | ✅ 空闲 |
| write | 0 | 0 | 0 | ✅ 空闲 |
| management | 1 | 0 | 0 | ✅ 正常 |
| 其他 | 0 | 0 | 0 | ✅ 空闲 |
所有线程池都很健康,没有队列堆积,没有请求被拒绝。说明当前负载很轻,集群处理能力充足。
⚠️ rejected 不为 0 说明请求被拒绝了,这是严重问题,需要立即排查是资源不足还是请求量过大。
索引级别监控:定位问题索引
集群整体健康不代表每个索引都正常,单独检查索引状态很有必要:
bash
# 查看所有索引,手动筛选异常状态
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
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 状态。
bash
# 按大小排序,找出最大的索引
GET _cat/indices?v&s=store.size:desc&h=index,health,pri,rep,docs.count,store.size
💡 示例输出(生产环境可能看到类似这样的大索引):
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 |
对比历史数据 |
分片分布监控:避免热点节点
分片分布不均会导致某些节点负载过高:
bash
GET _cat/shards?v&s=store:desc&h=index,shard,prirep,state,docs,store,node
💡 示例输出(生产环境可能看到类似这样的分片分布):
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
bash
# 查看每个节点的分片数量
GET _cat/allocation?v
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-load、products以及 ILM 相关索引配置了 1 个副本,但当前是单节点集群,副本无法分配到其他节点。这在单节点测试环境是正常的。
分片分布健康指标:
| 指标 | 健康标准 |
|---|---|
| 节点间分片数差异 | < 20% |
| 单节点最大分片数 | < 1000 |
| UNASSIGNED 分片 | 应为 0 |
💡 小贴士 :如果发现分片分布不均,可以用
POST _cluster/reroute手动调整,或调整cluster.routing.allocation相关配置。
查询性能监控:定位慢查询
搜索变慢是最常见的用户投诉,这些指标帮你快速定位:
bash
GET _nodes/stats/indices/search
json
{
"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
}
}
}
关键性能指标计算:
平均查询耗时 = 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 的核心机制,但频繁合并会严重影响写入性能:
bash
GET _nodes/stats/indices/merges
json
{
"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。
bash
# 查看每个索引的段数量
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 |
| 索引状态 | yellow | red |
常用命令速查表
bash
# 🧵 线程池状态
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):
json
{
"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,如果你之前用过这些产品,可以无缝迁移。
参考文档: