公司目前所使用的Elasticsearch(以下简称ES)版本是在2015年的时候选择的,当时选择了ES的最新版本1.5.2。随着ES官方的快速发展,ES也已经推出了很多新的版本,这些新版本往往伴随着一些新特性的发布以及性能的提升,为了使用到这些新特性,我们决定将ES的版本升级到7.5.2。
ES版本升级会遇到API不兼容的问题,我们的解决办法是在业务和ES之间增加一层_搜索平台_来做接口兼容。此外我们在版本升级之前还需要了解一下ES-7.5.2相对于ES-1.5.2有多少性能提升,所以我们需要针对这两个版本做一下性能测试并对结果进行对比。我们使用如下的四台负载来做性能测试
序号 | 节点IP | CPU型号 | CPU核数 | 内存 | 硬盘 | 操作系统 |
---|---|---|---|---|---|---|
1 | 172.19.66.58 | Intel(R) Xeon(R) CPU E5645 @2.40GHz | 2 | 3079520kB | 14G | GNU/Linux 3.10.0-957.21.3.el7.x86_64 |
2 | 172.19.66.70 | Intel(R) Xeon(R) CPU E5645 @2.40GHz | 2 | 3079524kB | 14G | GNU/Linux 3.10.0-957.21.3.el7.x86_64 |
3 | 172.19.66.77 | Intel(R) Xeon(R) CPU E5645 @2.40GHz | 2 | 3079524kB | 14G | GNU/Linux 3.10.0-957.21.3.el7.x86_64 |
4 | 172.19.66.133 | Intel(R) Xeon(R) CPU E5645 @2.40GHz | 2 | 3079524kB | 14G | GNU/Linux 3.10.0-957.21.3.el7.x86_64 |
使用time和dd命令测试负载的磁盘性能
# 测试磁盘的写入性能time dd if=/dev/zero of=test.data bs=8k count=10000 oflag=direct# 测试磁盘的读取性能time dd if=test.data of=/dev/null bs=8k count=10000 iflag=direct
通过测试可知以上四台负载的磁盘读写性能基本一致。
1号和2号节点安装ES-1.5.2集群,3号和4号节点安装ES-7.5.2集群。两个集群各自的两个节点均设置为master-eligible和data节点,并且JVM的堆内存都设置为1GB。分别向两个集群写入相同的测试数据112万条,对于text类型两个集群都使用ES默认的分词器。两个集群的两个索引的mapping基本上一致,我把1.5.2和7.5.2这两个索引的mapping都放在了gist上面以供参考。
我们使用 ApacheBench (ab) 来实现压测功能,为了方便操作我们利用ab实现了一个测试脚本 test.sh,在测试脚本中我们使用了query.json文件中的ES查询DSL来实现ES不同类型查询的性能测试,后面我们会修改query.json文件中的DSL来实现不同的查询测试。
压测使用的客户机为MacBookPro,客户机和ES集群位于同一个局域网,因此可以保证网络带宽不会成为瓶颈。客户机的具体配置如下
macOs Catalina 10.15.4 (19E287)MacBook Pro (Retina, 13-inch, Early 2015)2.7 GHz Dual-Core Intel Core i58 GB 1867 MHz DDR3
具体的测试结果如下,我们修改query.json的DSL来实现不同类型操作的测试。
1 | { |
修改query.json的内容如上并且执行命令
./test.sh
随后我们可以得到脚本的执行结果,因为执行结果内容比较多所以我们只挑一些关键性的部分进行了解。完整的执行结果可以在 gist上面 看到。
Elasticsearch-1.5.2 >>> 172.19.66.70Requests per second: 165.87 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 34366% 39975% 42180% 45490% 54795% 62098% 68799% 784100% 905 (longest request)Elasticsearch-7.5.2 >>> 172.19.66.77Requests per second: 1049.51 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 5366% 6175% 6880% 7390% 8795% 10098% 11899% 129100% 202 (longest request)
可以看到在并发为60的情况下,执行压测10秒钟,1.5.2的QPS为165.87,7.5.2的QPS为1049.51,此外7.5.2的99%的请求耗时都是在130ms以下的,由此可以证明7.5.2相较于1.5.2在term查询上确实有很大的性能提升。
query.json
1 | { |
性能测试结果
Elasticsearch-1.5.2 >>> 172.19.66.70Requests per second: 1237.86 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 4566% 5275% 5880% 6290% 7595% 8598% 10199% 113100% 189 (longest request)Elasticsearch-7.5.2 >>> 172.19.66.77Requests per second: 1099.03 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 4766% 5475% 5980% 6390% 7595% 8698% 10299% 120100% 166 (longest request)
可以看出7.5.2在range查询上有一定的性能提升,但是提升并不明显。
query.json
1 | { |
性能测试结果
Elasticsearch-1.5.2 >>> 172.19.66.70Requests per second: 789.62 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 7466% 9275% 10780% 11590% 13295% 14898% 16999% 187100% 336 (longest request)Elasticsearch-7.5.2 >>> 172.19.66.77Requests per second: 1229.56 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 4466% 5275% 5780% 6290% 7295% 8598% 10799% 135100% 275 (longest request)
由上面的结果可见7.5.2对match查询也是有一定的性能提升的。
query.json
1 | { |
性能测试结果
Elasticsearch-1.5.2 >>> 172.19.66.70Requests per second: 32.67 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 183866% 193875% 197080% 197290% 242795% 255598% 259799% 3486100% 3806 (longest request)Elasticsearch-7.5.2 >>> 172.19.66.77Requests per second: 1393.98 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 4166% 4875% 5380% 5690% 6595% 7498% 8499% 93100% 141 (longest request)
7.5.2在指标聚合上的速度提升也十分的可观。
query.json
1 | { |
性能测试结果
Elasticsearch-1.5.2 >>> 172.19.66.70Requests per second: 79.98 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 72166% 101575% 117180% 125890% 148895% 157198% 160099% 1618100% 1643 (longest request)Elasticsearch-7.5.2 >>> 172.19.66.77Requests per second: 1629.80 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 3466% 4075% 4580% 4890% 5795% 6598% 7799% 86100% 153 (longest request)
7.5.2在桶聚合上也有着很好的性能优化效果。
从上面的term、range、match、metric、bucket的测试结果中我们可以看到,除了range之外其余的几个DSL在7.5.2都有了较大的性能提升。但是我们也要清醒地认识到,我们在上面的单次性能测试中使用的都是完全一样的DSL,这就可能会使得ES中的缓存生效,因此该性能测试可能无法完全展现出真实环境中的ES性能,因为在真实环境中ES的缓存可能并不能像这里测试的这样完美的生效。
此外,由于这里的机器资源有限,我们只能做一个简单的性能对比实验,证明7.5.2的性能确实是优于1.5.2的。真正的ES-7.5.2集群的性能极限还要等到_搜索平台_的兼容性测试完成后,这时候我们可以搭建一个真正的生产环境的7.5.2集群,然后对此集群进行极限压测,等后面做了我会再做一份笔记。
上面我们测试了ES的数据检索和聚合的性能,下面我们也对ES的数据写入性能做一个测试。创建data.json并保存如下的数据
1 | { |
使用ab测试1.5.2的集群写入性能
ab -n 50000 -c 200 -p data.json -T 'application/json' http://172.19.66.70:9200/books/Book
性能报告如下
Time taken for tests: 26.680 secondsRequests per second: 1874.06 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 7266% 8575% 9580% 10190% 12395% 14798% 123699% 1276100% 3652 (longest request)
使用ab测试7.5.2的集群写入性能
ab -n 50000 -c 200 -p data.json -T 'application/json' http://172.19.66.77:9200/books/_doc
性能报告如下
Time taken for tests: 103.203 secondsRequests per second: 484.48 [#/sec] (mean)Percentage of the requests served within a certain time (ms)50% 34466% 38775% 43880% 47890% 61595% 73998% 97999% 1097100% 2436 (longest request)
很奇怪的是ES-7.5.2的数据写入性能明显低于ES-1.5.2,为了规避掉机器之间的细微的差异,我把ES-7.5.2安装在节点1和节点2之上,之后停止ES-1.5.2集群同时启动ES-7.5.2集群,然后把数据写到新的7.5.2的集群中去,测试结果和上面还是基本一致。具体原因暂时还不清楚,后面再做进一步的深入了解。
我们删除上面的测试中所创建的books索引,之后给每个索引只创建一条文档
ab -n 1 -c 1 -p data.json -T 'application/json' http://172.19.66.70:9200/books/Bookab -n 1 -c 1 -p data.json -T 'application/json' http://172.19.66.77:9200/books/_doc
只写入一条数据我们发现1.5.2也是快于7.5.2的集群的,之后我们使用如下接口观察我们写入的数据的段文件情况,首先是1.5.2集群
http://172.19.66.70:9200/books/_segments
得到1.5.2的段文件信息如下
1 | { |
从上面的结果中我们可以看到这条文档被保存到了books索引的0号分片中,这个分片包含了primary和replica两份数据,1号分片中的数据则为空。我们可以看到0号分片的主备两个分片的 segments.size_in_bytes 的值均为9870,这代表了segment在磁盘上占用的空间大小。
了解了以上信息之后,我们继续获得7.5.2的段文件信息
http://172.19.66.77:9200/books/_segments
得到的7.5.2的段文件信息如下
1 | { |
7.5.2集群的books索引的文档分配在了分片1上,同样分片1也包含了主副两个分片。我们可以看到7.5.2的段文件占用的磁盘空间为11863,比1.5.2的9870要大一些,这是为什么呢?按道理来说Lucene从版本4.10.4升级到版本8.3.0,占用空间应该有一定程度上的优化才对,至少也不应该是占用空间变大了啊。
通过查找资料,我们可以知道在新版本的Elasticsearch中,为了优化ES的排序和聚合的速度而引入了Doc values属性,该属性是在文档索引时生成的,目的是为了替代以前在文档查询时才生成的Fielddata属性。
我们可以对字段的mapping属性添加
"doc_values": false
这样可以禁用字段的doc_values属性,在禁用了7.5.2的字段的doc_values之后,段文件占用空间明显减小,索引速度也有明显的提升。
BUT!!!
通过以上的配置之后,7.5.2的数据索引速度仍然只是1.5.2的一半😶,具体原因还需进一步的分析😢。
5月19日补充:
关闭两个集群的refresh_interval(关闭自动refresh之后,写入到索引的数据不会被查询到,除非手动的执行了refresh操作之后才可以)
PUT /books/_settings{ "refresh_interval": -1}
同时关闭7.5.2的doc_values,并且只保存了long类型的数据以避免分词器的影响,之后测试结果发现仍然是7.5.2的时间更长。不过此时我们使用如下的接口查询索引的详细信息
GET /books/_stats
可以发现两个索引的 indexing.index_time_in_millis 的值其实是一样呢,这是为啥呢。。。
滴滴 ElasticSearch 平台跨版本升级以及平台重构之路
https://www.elastic.co/guide/en/elasticsearch/reference/7.5/query-dsl.html
https://www.elastic.co/guide/en/elasticsearch/reference/7.5/search-aggregations.html