ElasticSearch性能优化

ES对于其他的一些应用来说,能够优化的地方非常少,其实最大的优化就是给予它足够大的内存,我们说下其他一些优化。

一、慢查询日志

ES会自动开启慢查询日志,来查看插入搜索哪些性能比较慢,然后再考虑如何优化写入或搜索的性能。

在elasticsearch.yml中配置快慢的阈值,即多少秒算慢,需要写到日志里

1
2
3
4
5
6
7
8
9
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

对于慢查询日志的日志格式,是在log4j2.properties中配置,es默认会给出一些配置,可以根据自己的需要修改。

二、插入的优化

2.1.批量写入

对于需要批量插入数据时,相对于一条条插入,使用bulk效率更高,性能更高

并且使用多线程bulk请求。

2.2.增加refresh间隔

默认的refresh间隔是1s,用index.refresh_interval参数可以设置,这样会其强迫es每秒中都将内存中的数据写入磁盘中,创建一个新的segment file。

正是这个间隔,让我们每次写入数据后,1s以后才能看到。但是如果我们将这个间隔调大,比如30s,可以接受写入的数据30s后才看到,那么我们就可以获取更大的写入吞吐量,因为30s内都是写内存的,每隔30s才会创建一个segment file。

2.3.给filesystem cache更多的内存

2.4.使用自动生成的id

使用设置的id,es会多做一个查询此id是否存在的过程,而使用自动生成的便不会需要查询

三、查询的优化

查询的优化其实在前面的笔记已经说了,最重要的两点,内存,分页

3.1.优化内存

通过第四章ElasticSearch集群配置中的第八节深入document底层读写机制可用得知:

ES读取数据是基于磁盘的,如果每次读数据需要进行磁盘读取操作,非常耗时,但是如果给 filesystem cache 更多的内存,尽量让内存可以容纳所有的 idx segment file索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。

性能差距:我们之前很多的测试和压测,如果走磁盘一般肯定上秒,搜索性能绝对是秒级别的,1秒、5秒、10秒。但如果是走 filesystem cache,是走纯内存的,那么一般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。

3.2.数据预热

举个例子,拿微博来说,你可以把一些大V,平时看的人很多的数据,你自己提前后台搞个系统,每隔一会儿,自己的后台系统去搜索一下热数据,刷到 filesystem cache 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。

或者是电商,你可以将平时查看最多的一些商品,比如说 iphone 8,热数据提前后台搞个程序,每隔 1 分钟自己主动访问一次,刷到 filesystem cache 里去。

对于那些你觉得比较热的、经常会有人访问的数据,最好做一个专门的缓存预热子系统,就是对热数据每隔一段时间,就提前访问一下,让数据进入 filesystem cache 里面去。这样下次别人访问的时候,性能一定会好很多。

3.3.冷热分离

es 可以做类似于 mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在被预热之后,尽量都让他们留在 filesystem os cache 里,别让冷数据给冲刷掉

你看,假设你有 6 台机器,2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 shard。3 台机器放热数据 index,另外 3 台机器放冷数据 index。然后这样的话,你大量的时间是在访问热数据 index,热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 filesystem cache 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的 index 里的,跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据,90% 的人在访问热数据,也无所谓了。

3.4.分页问题

es查询分页原理:举例3个shard,3000条数据,查询from=100,size=10

  1. 因为from100,size10,即需要100-109的数据
  2. es协调节点向3个shard发出请求,要求获取每个shard的0-109的数据注意是0-109
  3. 每个shard接收到请求后,会创建一个from+size大小的priority queue,一个优先队列,将查询出的数据放入队列再全部返回给协调节点。
  4. 协调节点获取到这些数据,总数据量为330条,将这些数据放到自己的priority queue然后对这些数据进行排序
  5. 排序后将序号为100-109的数据返回给客户端

这时我们会发现,如果数据量增加到30万条,而用户需要最后10条,那么es的协调节点需要临时存储30万条数据且进行排序,会导致大量资源耗费,所以对于ES的分页,要尽量避免DEEP PAGING的情况。或者直接禁止分页,使用下拉滚动的情况,类似说知乎那样,需要用到scroll滚动查询