ElasticSearch教程FG019-ElasticSearch慢查询优化实战
内容简介:本文档风哥主要介绍ElasticSearch慢查询的识别、分析和优化方法。通过学习本文,您将掌握如何配置慢查询日志、识别慢查询、分析慢查询原因,并通过优化查询语句、索引结构和缓存策略等手段,提高ElasticSearch的查询性能。风哥教程参考ElasticSearch官方文档Slow Log部分。
Part01-基础概念与理论知识
1.1 慢查询的定义与影响
慢查询是指执行时间超过设定阈值的查询请求。在ElasticSearch中,慢查询会对系统性能产生以下影响:
- 占用过多的系统资源(CPU、内存、I/O)
- 影响其他查询的响应时间
- 可能导致集群负载过高,影响整体稳定性
- 降低用户体验,特别是在实时查询场景中
1.2 慢查询的原因分析
导致慢查询的常见原因包括:
- 查询语句复杂:使用了复杂的嵌套查询、深度聚合等
- 索引设计不合理:缺少必要的索引、字段类型选择不当
- 数据量过大:查询涉及的数据量过大,没有合理的过滤条件
- 硬件资源不足:CPU、内存、磁盘I/O等资源不足
- 缓存未命中:查询结果没有被缓存,每次都需要重新计算
- 全表扫描:查询没有使用索引,导致全表扫描
1.3 慢查询日志配置
ElasticSearch提供了慢查询日志功能,可以记录执行时间超过设定阈值的查询。配置步骤如下:
vi /es/app/elasticsearch-8.10.0/config/elasticsearch.yml
# 添加慢查询日志配置
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
index.search.slowlog.threshold.query.trace: 500ms
index.search.slowlog.threshold.fetch.warn: 1s
index.search.slowlog.threshold.fetch.info: 800ms
index.search.slowlog.threshold.fetch.debug: 500ms
index.search.slowlog.threshold.fetch.trace: 200ms
index.search.slowlog.level: info
index.search.slowlog.source: 1000
Part02-生产环境规划与建议
2.1 慢查询阈值设置
在生产环境中,建议根据业务场景设置合理的慢查询阈值:
- 实时查询场景:阈值设置为100-500ms
- 非实时查询场景:阈值设置为1-5s
- 批量查询场景:阈值设置为5-10s
2.2 慢查询监控策略
建议采用以下监控策略:
- 定期分析慢查询日志,识别高频慢查询
- 设置慢查询告警,当慢查询数量超过阈值时及时通知
- 建立慢查询基线,监控慢查询性能趋势
- 对慢查询进行分类,针对不同类型的慢查询采取相应的优化措施
2.3 性能优化规划
性能优化规划建议:
- 短期优化:优化查询语句,添加必要的索引
- 中期优化:调整索引结构,优化缓存策略
- 长期优化:调整集群架构,升级硬件资源
Part03-生产环境项目实施方案
3.1 慢查询识别与分析
识别和分析慢查询的步骤:
tail -f /es/fgdata/logs/fgedu-cluster_index_search_slowlog.log
执行后输出:
curl -X GET “http://192.168.1.10:9200/_tasks?actions=*search*&detailed=true&pretty”
3.2 查询语句优化
查询语句优化措施:
- 使用过滤查询:将不需要评分的条件放在filter中,利用过滤器缓存
- 减少返回字段:只返回需要的字段,减少网络传输
- 合理设置size:避免一次性返回过多结果
- 使用批量查询:将多个查询合并为一个批量请求
- 避免使用通配符查询:通配符查询(如*keyword*)会导致全表扫描
- 使用term查询:对于精确匹配,使用term查询而不是match查询
3.3 索引结构优化
索引结构优化措施:
- 合理设置分片数:根据数据量和节点数设置合适的分片数
- 使用合适的字段类型:根据数据类型选择合适的字段类型
- 添加适当的索引:为常用查询字段添加索引
- 使用复合索引:对于多字段查询,使用复合索引
- 优化映射:合理设置字段的analyzer、search_analyzer等
3.4 缓存策略优化
缓存策略优化措施:
- 利用查询缓存:对于相同的查询,利用查询缓存
- 利用过滤器缓存:对于过滤条件,利用过滤器缓存
- 使用索引缓存:合理设置索引缓存大小
- 使用字段数据缓存:对于排序和聚合操作,使用字段数据缓存
Part04-生产案例与实战讲解
4.1 慢查询日志分析实战
分析慢查询日志,识别性能问题:
grep “took” /es/fgdata/logs/fgedu-cluster_index_search_slowlog.log | sort -k3 -n -r | head -10
执行后输出:
[2024-01-01T10:01:00,000][WARN ][index.search.slowlog.query] [fgedu-node1] [fgedu-products][0] took[450ms], took_millis[450], total_hits[800], types[], stats[], search_type[QUERY_THEN_FETCH], total_shards[5], source[{“query”:{“bool”:{“must”:[{“match”:{“product_name”:”ElasticSearch”}},{“match”:{“description”:”实战”}}]}}}], id[],
[2024-01-01T10:02:00,000][WARN ][index.search.slowlog.query] [fgedu-node1] [fgedu-products][0] took[400ms], took_millis[400], total_hits[500], types[], stats[], search_type[QUERY_THEN_FETCH], total_shards[5], source[{“query”:{“wildcard”:{“product_name”:”*Elastic*”}}}], id[],
4.2 复杂查询优化实战
优化复杂查询:
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“query”: {
“bool”: {
“must”: [
{
“match”: {
“product_name”: “ElasticSearch”
}
},
{
“match”: {
“description”: “实战”
}
}
],
“filter”: [
{
“range”: {
“price”: {
“lte”: 100
}
}
}
]
}
},
“sort”: [
{
“price”: {
“order”: “asc”
}
}
],
“size”: 10
}’
执行后输出:
“took” : 450,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 1,
“relation” : “eq”
},
“max_score” : null,
“hits” : [
{
“_index” : “fgedu-products”,
“_id” : “1”,
“_score” : null,
“_source” : {
“product_id” : “P001”,
“product_name” : “ElasticSearch实战指南”,
“price” : 89.9,
“category” : “技术书籍”,
“description” : “ElasticSearch实战指南,详细介绍ElasticSearch的使用方法和最佳实践”
},
“sort” : [
89.9
]
}
]
}
}
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“query”: {
“bool”: {
“must”: [
{
“match”: {
“product_name”: “ElasticSearch”
}
}
],
“filter”: [
{
“match”: {
“description”: “实战”
}
},
{
“range”: {
“price”: {
“lte”: 100
}
}
}
]
}
},
“_source”: [“product_id”, “product_name”, “price”],
“sort”: [
{
“price”: {
“order”: “asc”
}
}
],
“size”: 10
}’
执行后输出:
“took” : 50,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 1,
“relation” : “eq”
},
“max_score” : null,
“hits” : [
{
“_index” : “fgedu-products”,
“_id” : “1”,
“_score” : null,
“_source” : {
“product_id” : “P001”,
“product_name” : “ElasticSearch实战指南”,
“price” : 89.9
},
“sort” : [
89.9
]
}
]
}
}
4.3 聚合查询优化实战
优化聚合查询:
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“size”: 0,
“aggs”: {
“category_stats”: {
“terms”: {
“field”: “category”
},
“aggs”: {
“avg_price”: {
“avg”: {
“field”: “price”
}
},
“max_price”: {
“max”: {
“field”: “price”
}
},
“min_price”: {
“min”: {
“field”: “price”
}
}
}
}
}
}’
执行后输出:
“took” : 300,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 1000,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“category_stats” : {
“doc_count_error_upper_bound” : 0,
“sum_other_doc_count” : 0,
“buckets” : [
{
“key” : “技术书籍”,
“doc_count” : 500,
“avg_price” : {
“value” : 99.9
},
“max_price” : {
“value” : 199.9
},
“min_price” : {
“value” : 49.9
}
},
{
“key” : “文学书籍”,
“doc_count” : 300,
“avg_price” : {
“value” : 69.9
},
“max_price” : {
“value” : 129.9
},
“min_price” : {
“value” : 29.9
}
},
{
“key” : “儿童书籍”,
“doc_count” : 200,
“avg_price” : {
“value” : 39.9
},
“max_price” : {
“value” : 89.9
},
“min_price” : {
“value” : 19.9
}
}
]
}
}
}
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“size”: 0,
“aggs”: {
“category_stats”: {
“terms”: {
“field”: “category”,
“size”: 10
},
“aggs”: {
“avg_price”: {
“avg”: {
“field”: “price”
}
}
}
}
}
}’
执行后输出:
“took” : 50,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 1000,
“relation” : “eq”
},
“max_score” : null,
“hits” : [ ]
},
“aggregations” : {
“category_stats” : {
“doc_count_error_upper_bound” : 0,
“sum_other_doc_count” : 0,
“buckets” : [
{
“key” : “技术书籍”,
“doc_count” : 500,
“avg_price” : {
“value” : 99.9
}
},
{
“key” : “文学书籍”,
“doc_count” : 300,
“avg_price” : {
“value” : 69.9
}
},
{
“key” : “儿童书籍”,
“doc_count” : 200,
“avg_price” : {
“value” : 39.9
}
}
]
}
}
}
4.4 深分页优化实战
优化深分页查询:
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“query”: {
“match_all”: {}
},
“from”: 10000,
“size”: 10
}’
执行后输出:
“took” : 2000,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 100000,
“relation” : “eq”
},
“max_score” : 1.0,
“hits” : [
{
“_index” : “fgedu-products”,
“_id” : “10001”,
“_score” : 1.0,
“_source” : {
“product_id” : “P10001”,
“product_name” : “示例产品10001”,
“price” : 99.9,
“category” : “技术书籍”
}
},
…
]
}
}
# 首先获取第一页,并记录最后一个文档的排序值
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“query”: {
“match_all”: {}
},
“sort”: [
{“_id”: “asc”}
],
“size”: 10
}’
执行后输出:
“took” : 10,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 100000,
“relation” : “eq”
},
“max_score” : null,
“hits” : [
{
“_index” : “fgedu-products”,
“_id” : “1”,
“_score” : null,
“_source” : {
“product_id” : “P0001”,
“product_name” : “示例产品0001”,
“price” : 99.9,
“category” : “技术书籍”
},
“sort” : [“1”]
},
…,
{
“_index” : “fgedu-products”,
“_id” : “10”,
“_score” : null,
“_source” : {
“product_id” : “P0010”,
“product_name” : “示例产品0010”,
“price” : 99.9,
“category” : “技术书籍”
},
“sort” : [“10”]
}
]
}
}
curl -X GET “http://192.168.1.10:9200/fgedu-products/_search” -H “Content-Type: application/json” -d ‘{
“query”: {
“match_all”: {}
},
“sort”: [
{“_id”: “asc”}
],
“search_after”: [“10”],
“size”: 10
}’
执行后输出:
“took” : 10,
“timed_out” : false,
“_shards” : {
“total” : 5,
“successful” : 5,
“skipped” : 0,
“failed” : 0
},
“hits” : {
“total” : {
“value” : 100000,
“relation” : “eq”
},
“max_score” : null,
“hits” : [
{
“_index” : “fgedu-products”,
“_id” : “11”,
“_score” : null,
“_source” : {
“product_id” : “P0011”,
“product_name” : “示例产品0011”,
“price” : 99.9,
“category” : “技术书籍”
},
“sort” : [“11”]
},
…
]
}
}
Part05-风哥经验总结与分享
5.1 慢查询优化最佳实践
- 定期分析慢查询日志:及时发现和解决慢查询问题
- 优化查询语句:使用过滤查询,减少返回字段,避免使用通配符查询
- 合理设计索引:为常用查询字段添加索引,使用合适的字段类型
- 利用缓存:充分利用ElasticSearch的各种缓存机制
- 优化聚合查询:使用近似聚合,限制聚合结果数量
- 优化深分页:使用search_after代替from/size进行深分页
- 监控系统性能:建立完善的监控体系,及时发现性能问题
5.2 常见慢查询场景与解决方案
- 通配符查询:避免使用通配符查询,或使用前缀查询代替
- 深度聚合:减少聚合的深度和复杂度,使用近似聚合
- 深分页:使用search_after或scroll API代替from/size
- 复杂布尔查询:简化查询结构,将过滤条件放在filter中
- 全表扫描:为查询字段添加索引,优化查询条件
5.3 性能监控与持续优化
- 建立性能基线:记录正常运行时的性能指标,作为参考标准
- 设置性能告警:当性能指标超过阈值时及时告警
- 定期性能测试:定期进行性能测试,发现性能瓶颈
- 持续优化:根据业务需求和数据变化,持续优化查询和索引
- 文档化优化经验:记录优化过程和结果,形成优化指南
更多视频教程www.fgedu.net.cn
学习交流加群风哥微信: itpux-com
学习交流加群风哥QQ113257174
风哥提示:慢查询优化是一个持续的过程,需要根据实际情况不断调整和改进
更多学习教程公众号风哥教程itpux_com
from ElasticSearch视频:www.itpux.com
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
