获取OpenSearch集群查询资源占用情况
在日常运维OpenSearch集群的过程中,运维人员经常遇到因查询导致CPU占用率高的问题。当前,定位此类问题的方法较为繁琐,需要通过OpenSearch API获取正在运行的任务,再结合hot threads信息,才能确定具体是哪些查询语句导致了CPU占用率升高。为了提高运维效率,CSS服务提供了支持查询资源占用溯源的功能。启用该功能后,运维人员可以通过API获取到最近时延最大、消耗CPU和内存最多的查询语句,并支持基于时间进行过滤从而快速定位到问题查询,提升故障排查的效率和准确性。
原理介绍
查询资源占用溯源功能旨在帮助用户识别和优化高资源消耗的查询,提高系统性能和资源利用率。该功能适用于大数据分析、日志处理等场景。
在查询执行阶段,系统会记录每个子阶段(如Query、Fetch、Scroll等)的资源消耗情况,包括CPU使用率、内存占用等。这些数据会以固定时间窗口(如5分钟)为单位进行统计,统计结果中消耗最高的查询语句会被持久化存储在Top查询索引中,以便后续分析。Top查询索引会每天新建一个,用于存储当天的查询资源消耗统计数据,命名格式是top-queries-xxx(xxx是日期)。
TopN查询是指按指定指标(如CPU、内存或延迟)对查询语句进行排序,返回消耗最高的前N条记录。默认情况下,系统按延迟指标进行排序。
约束限制
- 查询资源占用溯源的功能会增加内存缓存字段类型信息,对集群性能会有影响。
- 满足以下条件的OpenSearch集群默认启用查询资源占用溯源功能:集群版本号为2.19.0,镜像版本号不低于2.19.0_25.9.0_xxx。
修改查询资源占用溯源的配置
OpenSearch支持通过Dashboards或API修改查询资源占用溯源的配置。
- 方式一:通过OpenSearch Dashboards修改配置
- 登录云搜索服务管理控制台。
- 在左侧导航栏,选择“集群管理 > OpenSearch”。
- 在集群列表,选择目标集群,单击操作列的“Dashboards”,登录OpenSearch Dashboards。
- 在OpenSearch Dashboards左侧导航栏选择“OpenSearch Plugins > Query Insights”,进入Query insights页面。
- 选择“Configuration”页签,修改查询资源占用溯源的配置。
表1 配置参数说明 参数
说明
Metric Type
指定要配置的指标类型。
- Latency:延迟
- CPU:CPU使用率
- Memory:内存使用率
Enabled
是否开启对应Metric Type的TopN查询监控。
Value of N (count)
指定每个时间窗监控TopN查询请求的个数。
取值范围:1~100
默认值:10
Window size
窗口大小。监控数据会以固定的时间窗口(如5分钟)为单位进行统计。
取值范围:1m(1分钟)、5m(5分钟)、10m(10分钟)、30m(半小时)或xh(x小时,x支持1~24)
默认值:5m
Group By
指定分组依据的类型。
取值范围:
- None(默认值):不分组。
- Similarity:按查询特征的相似度进行分组。同一个窗口中针对同一个查询特征的多个请求只显示第一个查询请求。默认查询特征是完整查询结构(结构+字段+类型)。
查询分组功能的详细介绍请参见查询分组介绍。
Exporter
是否将数据存储到Top查询索引。
- Local Index(默认值):查询资源占用溯源数据存档到Top查询索引top-queries-xxx。
- None:查询资源占用溯源数据不存档到Top查询索引top-queries-xxx,即只保留最近两个窗口的数据在内存,超过窗口范围的数据直接丢弃。
Delete After (days)
Top查询索引top-queries-xxx的保留天数,到期会被删除。
取值范围:1~180
默认值: 7
- 修改完成后,单击“Save”保存配置以确保修改的参数生效。
- 方式二:通过API修改配置
执行如下命令可修改查询资源占用溯源的配置,以合理监控资源使用情况并优化资源管理:
PUT _cluster/settings { "persistent": { "search.insights.top_queries.cpu.enabled": true, "search.insights.top_queries.cpu.window_size": "10m", "search.insights.top_queries.cpu.top_n_size": 20, "search.insights.top_queries.exporter.delete_after_days": 8, "search.insights.top_queries.group_by": "none" } }表2 配置项说明 配置项
类型
描述
search.insights.top_queries.<metric>.enabled
Boolean
是否开启对应metric的TopN查询监控。
metric支持:latency(延迟)、cpu(CPU使用率)、memory(内存使用率)
- true(默认值):开启查询监控。
- false:关闭查询监控。
search.insights.top_queries.<metric>.window_size
String
窗口大小。监控数据会以固定的时间窗口(如5分钟)为单位进行统计。
metric支持:latency(延迟)、cpu(CPU使用率)、memory(内存使用率)
取值范围:1m(1分钟)、5m(5分钟)、10m(10分钟)、30m(半小时)或xh(x小时,x支持1~24)
默认值:5m
search.insights.top_queries.<metric>.top_n_size
Integer
每个时间窗监控TopN查询请求的个数。
例如,配置为20表示每个时间窗只监控Top20的查询数据。
metric支持:latency(延迟)、cpu(CPU使用率)、memory(内存使用率)
取值范围:1~100
默认值:10
search.insights.top_queries.exporter.delete_after_days
Integer
Top查询索引top-queries-xxx的保留时间,到期会被删除。
例如,配置为8表示数据只保留8天。
取值范围:1~180
默认值: 7
单位:天
search.insights.top_queries.group_by
String
是否启用查询分组功能。
取值范围:
- none(默认值):不分组。
- similarity:按查询特征的相似度进行分组。同一个窗口中针对同一个查询特征的多个请求只显示第一个查询请求。
查询分组功能的详细介绍请参见查询分组介绍。
search.insights.top_queries.grouping.attributes.field_name
Boolean
查询特征是否区分查询字段名字。
当“search.insights.top_queries.group_by”为“similarity”时此配置才生效。
- true(默认值):区分查询字段名。
- false:忽略查询字段名。
search.insights.top_queries.grouping.attributes.field_type
Boolean
查询特征是否区分查询字段的类型。
当“search.insights.top_queries.group_by”为“similarity”时此配置才生效。
- true(默认值):区分查询字段类型。
- false:忽略查询字段类型。
获取查询资源的占用情况
OpenSearch支持通过Dashboards或API获取查询资源的占用情况。
- 方式一:通过OpenSearch Dashboards获取查询资源的占用情况
- 登录云搜索服务管理控制台。
- 在左侧导航栏,选择“集群管理 > OpenSearch”。
- 在集群列表,选择目标集群,单击操作列的“Dashboards”,登录OpenSearch Dashboards。
- 在OpenSearch Dashboards左侧导航栏选择“OpenSearch Plugins > Query Insights”,进入Query insights页面。
- 在“Top N queries”页签,可以搜索并查看当前TopN的查询资源占用情况,以评估查询性能和资源使用效率。单击“Id”进入查询详情页面,可以查看查询语句、执行时间和资源占用情况。
- 方式二:通过API获取查询资源的占用情况
执行如下命令获取指定时间范围内某查询资源的占用情况:
GET _insights/top_queries?type=cpu&from=2025-12-02T00:00:00.000Z&to=2025-12-02T17:00:00.000Z
表3 请求参数说明 参数
说明
type
指定某一查询资源的TopN情况。
取值范围:latency(延迟)、cpu(CPU使用率)、memory(内存使用率)
默认值: latency
from
指定查询时间范围的开始值。
from和to必须同时配置才生效。
默认值:无,不指定则取最近两个窗口的TopN。
to
指定查询时间范围的结束值。
from和to必须同时配置才生效。
默认值:无,不指定则取最近两个窗口的TopN。
返回示例:
{ "top_queries": [ { "timestamp": 1764662136273, // 查询语句发生的时间戳 "date": "2025-12-02 07:55:36Z", // 查询语句发生的时间 "id": "4a5b4b1e-b502-4621-a5c1-09b8d9a1b81c", // 查询语句的唯一ID "task_resource_usages": [ { "action": "indices:data/read/search[phase/query]", // Query阶段在节点FB2ixw4IQCuXzCR83GT5Yg上的CPU消耗和内存消耗 "taskId": 1877927, "parentTaskId": 111295, "nodeId": "FB2ixw4IQCuXzCR83GT5Yg", "taskResourceUsage": { "cpu_time_in_nanos": 3017078, "memory_in_bytes": 102360 } }, { "action": "indices:data/read/search[phase/query]", // Query阶段在节点FB2ixw4IQCuXzCR83GT5Yg上的CPU消耗和内存消耗 "taskId": 1877926, "parentTaskId": 111295, "nodeId": "FB2ixw4IQCuXzCR83GT5Yg", "taskResourceUsage": { "cpu_time_in_nanos": 5618940, "memory_in_bytes": 271680 } }, { "action": "indices:data/read/search[phase/query]", // Query阶段在节点2ICOHICoSS26YeQu5PIrlg上的CPU消耗和内存消耗 "taskId": 107710, "parentTaskId": 111295, "nodeId": "2ICOHICoSS26YeQu5PIrlg", "taskResourceUsage": { "cpu_time_in_nanos": 8703914, "memory_in_bytes": 501560 } }, { "action": "indices:data/read/search[phase/fetch/id]", // Fetch阶段在节点FB2ixw4IQCuXzCR83GT5Yg上的CPU消耗和内存消耗 "taskId": 1877928, "parentTaskId": 111295, "nodeId": "FB2ixw4IQCuXzCR83GT5Yg", "taskResourceUsage": { "cpu_time_in_nanos": 424055, "memory_in_bytes": 59000 } }, { "action": "indices:data/read/search[phase/fetch/id]", // Fetch阶段在节点2ICOHICoSS26YeQu5PIrlg上的CPU消耗和内存消耗 "taskId": 107711, "parentTaskId": 111295, "nodeId": "2ICOHICoSS26YeQu5PIrlg", "taskResourceUsage": { "cpu_time_in_nanos": 1279677, "memory_in_bytes": 337504 } }, { "action": "indices:data/read/search", // 查询开始阶段在接入节点gzsjh_47SjCe6QFs9pKjEg上的CPU消耗和内存消耗 "taskId": 111295, "parentTaskId": -1, "nodeId": "gzsjh_47SjCe6QFs9pKjEg", "taskResourceUsage": { "cpu_time_in_nanos": 297268, "memory_in_bytes": 8632 } } ], "source": { // 具体的查询语句 "query": { "match": { "message": { "query": "http", "operator": "OR", "prefix_length": 0, "max_expansions": 50, "fuzzy_transpositions": true, "lenient": false, "zero_terms_query": "NONE", "auto_generate_synonyms_phrase_query": true, "boost": 1 } } } }, "indices": [ // 查询的索引 "log1" ], "total_shards": 3, // 查询的总分片数 "phase_latency_map": { // 查询各个阶段的耗时 "expand": 0, // expand阶段耗时 "query": 16, // Query阶段耗时 "fetch": 3 // Fetch阶段耗时 }, "labels": {}, "group_by": "NONE", // 查询分组类别 "node_id": "gzsjh_47SjCe6QFs9pKjEg", // 接收到请求的节点ID "search_type": "query_then_fetch", // 查询类型 "measurements": { // 查询指标 "memory": { // 内存消耗 "number": 1280736, "count": 1, "aggregationType": "NONE" }, "latency": { // 耗时 "number": 20, "count": 1, "aggregationType": "NONE" }, "cpu": { // CPU消耗 "number": 19340932, "count": 1, "aggregationType": "NONE" } } } ] }
获取查询资源占用溯源插件的资源消耗情况
执行如下命令以获取查询资源占用溯源插件的资源消耗情况:
GET _insights/health_stats
返回示例:
{
"QDyhJ8Q6Td2acc3KGQ43bQ" : {
"ThreadPoolInfo" : {
"query_insights_executor" : { // 插件专用队列,用于执行分析top query的任务
"type" : "scaling",
"core" : 1,
"max" : 1,
"keep_alive" : "5m",
"queue_size" : -1
}
},
"QueryRecordsQueueSize" : 0, // 当前在query_insights_executor队列中未处理的任务数
"TopQueriesHealthStats" : {
"latency" : {
"TopQueriesHeapSize" : 0, // 存储top queries占用的内存
"QueryGroupCount_Total" : 0, // 开启分组功能后当前在内存中的分组数
"QueryGroupCount_MaxHeap" : 0 // 开启分组功能后当前在内存中的分组占用的内存
},
"cpu" : {
"TopQueriesHeapSize" : 0,
"QueryGroupCount_Total" : 0,
"QueryGroupCount_MaxHeap" : 0
},
"memory" : {
"TopQueriesHeapSize" : 0,
"QueryGroupCount_Total" : 0,
"QueryGroupCount_MaxHeap" : 0
}
},
"FieldTypeCacheStats" : { // 缓存状态统计,启用查询分组时会将字段的mapping做缓存,避免每次查询都去获取mapping
"size_in_bytes" : 0,
"entry_count" : 0,
"evictions" : 0,
"hit_count" : 0,
"miss_count" : 0
}
}
}
查询分组介绍
当某单一查询持续占用资源时,TopN统计结果可能被该查询垄断,导致其他查询信息被隐藏。查询分组功能通过特征匹配将同类查询归为一组,确保每个分组在TopN中仅显示第一个查询请求。
|
分组模式 |
描述 |
|---|---|
|
完整查询结构(结构+字段+类型) |
精准匹配字段类型。 |
|
仅查询结构 |
忽略字段名和类型差异,仅区分查询逻辑结构。 |
|
仅查询结构+字段 |
忽略字段类型差异,区分查询逻辑结构和字段名。 |
|
仅查询结构+类型 |
忽略字段名差异,区分查询逻辑结构和字段类型。 |
启用字段类型匹配时,系统会缓存字段类型信息以提升分组效率,适用于字段类型不经常变化的场景。
配置示例
例如某个索引的mapping如下:
"mappings": {
"properties": {
"field1": {
"type": "keyword"
},
"field2": {
"type": "text"
},
"field3": {
"type": "text"
},
"field4": {
"type": "long"
}
}
}
对索引执行如下查询:
{
"query": {
"bool": {
"must": [
{
"term": {
"field1": "example_value"
}
}
],
"filter": [
{
"match": {
"field2": "search_text"
}
},
{
"range": {
"field4": {
"gte": 1,
"lte": 100
}
}
}
],
"should": [
{
"regexp": {
"field3": ".*"
}
}
]
}
}
}
|
分组模式 |
特征内容 |
|---|---|
|
完整查询结构 |
bool []
must:
term [field1, keyword]
filter:
match [field2, text]
range [field4, long]
should:
regexp [field3, text] |
|
仅查询结构 |
bool
must:
term
filter:
match
range
should:
regexp |
|
仅查询结构+字段 |
bool []
must:
term [field1]
filter:
match [field2]
range [field4]
should:
regexp [field3] |
|
仅查询结构+类型 |
bool []
must:
term [keyword]
filter:
match [text]
range [long]
should:
regexp [text] |