获取Elasticsearch集群查询资源占用情况
在日常运维Elasticsearch集群的过程中,运维人员经常遇到因查询导致CPU占用率高的问题。当前,定位此类问题的方法较为繁琐,需要通过Elasticsearch API获取正在运行的任务,再结合hot threads信息,才能确定具体是哪些查询语句导致了CPU占用率升高。为了提高运维效率,CSS服务提供了支持查询资源占用溯源的功能。启用该功能后,运维人员可以通过API获取到最近时延最大、消耗CPU和内存最多的查询语句,并支持基于时间进行过滤从而快速定位到问题查询,提升故障排查的效率和准确性。
原理介绍
查询资源占用溯源功能旨在帮助用户识别和优化高资源消耗的查询,提高系统性能和资源利用率。该功能适用于大数据分析、日志处理等场景。
在查询执行阶段,系统会记录每个子阶段(如Query、Fetch、Scroll等)的资源消耗情况,包括CPU使用率、内存占用等。这些数据会以固定时间窗口(如5分钟)为单位进行统计,统计结果中消耗最高的查询语句会被持久化存储在Top查询索引中,以便后续分析。Top查询索引会每天新建一个,用于存储当天的查询资源消耗统计数据,命名格式是top-queries-xxx(xxx是日期)。
TopN查询是指按指定指标(如CPU、内存或延迟)对查询语句进行排序,返回消耗最高的前N条记录。默认情况下,系统按延迟指标进行排序。
约束限制
- 查询资源占用溯源的功能会增加内存缓存字段类型信息,对集群性能会有影响。
- 满足以下条件的Elasticsearch集群默认启用查询资源占用溯源功能:集群版本号为7.10.2,镜像版本号不低于7.10.2_25.9.0_xxx。
修改查询资源占用溯源的配置
执行如下命令可修改查询资源占用溯源的配置,以合理监控资源使用情况并优化资源管理:
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"
}
}
|
配置项 |
类型 |
描述 |
|---|---|---|
|
search.insights.top_queries.<metric>.enabled |
Boolean |
是否开启对应metric的TopN查询监控。 metric支持:latency(延迟)、cpu(CPU使用率)、memory(内存使用率)
|
|
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 |
是否启用查询分组功能。 取值范围:
查询分组功能的详细介绍请参见查询分组介绍。 |
|
search.insights.top_queries.grouping.attributes.field_name |
Boolean |
查询特征是否区分查询字段名字。 当“search.insights.top_queries.group_by”为“similarity”时此配置才生效。
|
|
search.insights.top_queries.grouping.attributes.field_type |
Boolean |
查询特征是否区分查询字段的类型。 当“search.insights.top_queries.group_by”为“similarity”时此配置才生效。
|
获取查询资源的占用情况
执行如下命令获取指定时间范围内某查询资源的占用情况:
GET _insights/top_queries?type=cpu&from=2025-12-02T00:00:00.000Z&to=2025-12-02T17:00:00.000Z
|
参数 |
说明 |
|---|---|
|
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] |