ES索引优化方案

定期Forcemerge

由于单个分片的开销取决于segment数量和segment大小,segment个数越多,单个shard内的搜索将会消耗更多的时间和内存,通过对索引进行forcemerge将shard里面的多个较小的segment合并为segment,减少segment个数有效的提升查询性能,降低时延。同时段合并也能够清除已经被标记为删除的文档,减少空间。

操作语句为
POST /index_name/_forcemerge?max_num_segments=1

注意:forcemerge是一个极其耗费资源的操作,建议在业务量降低的时候进行。
段合并过程中会占用磁盘IO,影响检索性能,如果系统已经查询比较慢了,此时进行段合并会加剧问题。
另外,段合并不是一锤子买卖,如果索引还有持续的数据写入或者更新,shard内的segment也会继续的多起来,这个时候就要进行例行的段合并操作了,可以定时的在业务低峰期自动执行。
如果集群负载比较重,可以只处理含删除数据的segment,不合并segment

POST /index_name/_forcemerge?only_expunge_deletes=true

数据删除时,Lucene只做标记删除,不实际删除segment的数据,设置only_expunge_deletes为true时,ES会创建一个新的不含删除数据的segment替换当前含删除数据的segment。
segment 归并的过程,需要先读取 segment,归并计算,再写一遍 segment,最后还要保证刷到磁盘。可以说,这是一个非常消耗磁盘 IO 和 CPU 的任务。所以,ES 提供了对归并线程的限速机制,确保这个任务不会过分影响到其他任务。
链接: 官方说明

Forcemerge提速

在 5.0 之前,归并线程的限速配置 indices.store.throttle.max_bytes_per_sec 是 20MB。对于写入量较大,磁盘转速较高,甚至使用 SSD 盘的服务器来说,这个限速是明显过低的。对于 Elastic Stack 应用,社区广泛的建议是可以适当调大到 100MB或者更高。

PUT /_cluster/settings 
{
    ""persistent"" : {
        ""indices.store.throttle.max_bytes_per_sec"" : ""200mb""
    }
}

链接: 官方说明

索引拆分或重构shard

查询结果匹配命中的数据越多,性能越差,时延耗时越高。
索引拆分主要是要从业务方面入手,缩小搜索的数据范围,降低查询结果匹配命中的数据。比如对于大索引,通过业务层次划分,每个业务数据独立为一个索引。对于时序数据,可以通过按照时间进行索引拆分,每天一个索引,搜索的时候默认只搜索最近几天的数据。
重构shard的主要目的是为了解决shard个数过多影响查询的场景,这种方案适合数据量小,基本没有写入的场景,比如索引的数据量比较小10GB,之前设置了10个shard,10个节点,其实可以通过reindex,将索引的shard调整为1个,配置9个副本来达到更好地效果。"

索引字段尽量用keyword

能够用keyword替换的数值型字段(byte, short, integer, long, float, double, ip and date)尽量用keyword替换
keyword类型的term query,ES使用的是倒排索引。倒排索引在内存中维护了词典和文档列表(Posting list)的关系,倒排索引本身是想通过精确匹配从词典中找到term,然后找到词的posting list合并。
数值类型为了能有效的支持范围查询,它的存储结构并不是倒排索引。从lucene6开始。数值型的存储结构使用的是一种BKD tree的结构,类似于mysql中的B+索引结构,但是BKD是针对多维空间的。如果是BKD tree,精确匹配需要通过树的查找算法进行查询,然后文档结果集合进行排序再返回,相比倒排索引的词典树+posting list+跳表还是要差不少。树形数据结构对范围查找非常友好,如果业务上使用了数值型字段但是又不使用范围查找,可以使用keyword替代。
boolean类型需要替换吗? boolean类型的储存和数值型不一样,在lucene底层,boolean类型的存储其实是用F替代false,T替代true,是有倒排索引的,默认情况下(index为true的时候)不需要用keyword替换boolean,另外boolean类型的docvalue字段是用0,1表示false和true的,在用script获取docvalue计算的时候要注意。

少用模糊匹配

ES中的模糊匹配主要包括 wildcard通配符,fuzzy查询两种。模糊匹配耗时会随着数据量线性增长,很多时候一个模糊查询下去,可以通过监控看见集群的资源使用率快速升高,比较坏的情况下还会触发GC,当查询并发上去后会导致CPU和load也一并上升。ES是通过倒排索引来加速查找的,模糊查询的语句会命中大量的term词,特别是前后*的查询,命中的倒排term更多,意味着更多的倒排链参与搜索,将会消耗的更多的磁盘IO、CPU、内存资源,严重的情况下,查询会导致集群不可用,中断业务。

要怎么优化,使用模糊的语句查询的业务需要深入分析。是否一定要通过模糊的方式才能命中自己想要的文档。一种好的做法是通过分词来达到模糊查找的效果,比如使用match,通过分词的方式能够充分的利用倒排索引的优势,减少命中不相关的term。另外如果一定要用模糊查询,尽量减少前后或者前的这种查询,使用后*的匹配。

尽量使用Filter过滤器

ES中有query context和filter context两种查询,query主要关注文档的相关性匹配度,需要计算得分来评估文档和查询子句的相关度。filter主要关注文档是否匹配,只要回答“是”或“否”的问题。
官网也对于这两种context进行详细的介绍地址,
链接: 官方说明
有这样一个数据结构:有四个字段 年龄,姓名,城市,地址

PUT test {
	"mappings": {
		"propertles": {
			"age": {
				"type": "Integer"
			},
			"name": {
				"type": "keyword"
			},
			"city": {
				"type": "keyword"
			},
			"address": {
				"type": "text"
			}
		}
	}

现在要查询姓名等于某一个值的查询语句
使用query 子句进行查询:

POST test / _search {
	"query": {
		"bool": {
			"should": [{
					"term": {
						"name:{
						"value": "lisi"
					}
				}
			}
		]
	}
}
}

使用的是filter 子句进行查询:

POST test / _search {
	"query": {
		"bool": {
			"filter": [{
					"term": {
						"name:{
						"value": "lisi"
					}
				}
			}
		]
	}
}
}

使用filter也能够得到想要的结果,要看业务场景是否需要打分排序。Filter是对结果集合的简单检查,filter、must_not计算速度相对打分bool子句中的should、 must更快,并且es将会缓存常用的filter结果集,提高过滤性能。对比之下,query子句中的shoud、must不仅要查找匹配的文档,还要计算每个文档的相关程度,这通常会使其比非评分文档更复杂,另外,查询结果不可缓存。"

固定查询范围

固定查询范围的核心是通过查询缓存来加速。有如下的查询语句,可以看下面的filter中的range语句,查询点击时刻一小时内的数据,因为每一个点击的时间不可控,这样相当于filter的条件一直在变。

GET product * /_search {
	"query": {
		"bool": {
			"must": [{
				"match": {
					"code": "xxxxx"
				}
			}],
			"filter": [{
				"range": {
					"@timestamp": {
						"gte": "2021-02-01 10:00:24",
						"lt": "2021-02-01 11:00:24"
					}
				}
			}]
		}
	}
}

在业务允许的范围内,如果能够固定时间范围,这样能够利用filter的缓存能力,加速查找,改成如下语句:

GET product * /_search {
	"query": {
		"bool": {
			"must": [{
				"match": {
					"code": "xxxxx"
				}
			}],
			"filter": [{
				"range": {
					"@timestamp": {
						"gte": "2021-02-01 10:00:00",
						"lt": "2021-02-01 11:00:00"
					}
				}
			}]
		}
	}
}
开启慢日志,定位慢请求语句

链接: link

通过profile Api查看查询语句执行信息

链接: 官方说明

硬件优化

影响查询的主要资源包括CPU、内存、磁盘IO三大资源,网络带宽一般不会成为瓶颈(云上都是10GE的网卡)。如果已经尝试了业务层面以及查询语句等等优化都不能达到业务期望的效果,可以尝试进行硬件升级。

硬件升级前,首先得找到影响查询性能的瓶颈点,对症下药。
如果是CPU或者内存资源不够,可以通过节点纵向扩容来解决(比如从2u16g节点变更到4u32g的节点)或者横向扩容来解决(5个节点扩容成10个也能够扩大集群的计算和内存资源),如果是磁盘性能不够,因为磁盘不能够直接变更类型,需要重新更换机器。一般是通过备份恢复功能,将集群数据迁入到磁盘更好地集群,比如从云盘到本地盘SSD的超高IO系列或者鲲鹏超高IO系列。"

缓存优化

预加载数据到文件缓存中
链接: 官方说明

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值