Elasticsearch调优
本章将叙述elasticsearch的调优,涉及JVM调优、热点线程、水平扩展(分片)、高负载场景调优、高查询场景调优。有关es的安装请参考Elasticsearch搜索引擎一文。
1.1 JVM调优
想必大家都知道,垃圾回收实现目标
:需要实现是小而多次的垃圾回收,而不是一次长时间的回收,从而保证应用在稳定的性能水平运行。
1.1.1 使用jstat
命令:jstat -gcutil pid 2000 1000
gcutils:表示监控垃圾回收器的工作;
2000:毫秒表示的采样周期;
1000:是采样的数量;
显示结果:
S0 S1 E O P YGC YGCT FGC FGCT GCT
- 调优分析(先年轻代,后老年代)
当S0、S2或者E列显示为100%(或很高时),并且垃圾回收器不能回收这些堆空间,那么,要么是年轻代太小需要增加(如果有充足的剩余物理内存),要么是内存太小问题。
当O列老年代显示100%(或很高)时,垃圾回收器努力回收它(频繁的垃圾回收),但却不能回收,那么大概意味着没有足够的堆空间。
1.1.2 使用jmap
命令:jmap -dump:file=/opt/heap.dump pid
- 调优分析
导入文件后,可以使用gcviewer工具导入进行分析。
1.2 避免内存交换
当物理内存数量不够或者操作系统某些原因认为把一部分RAM内存写入磁盘更好些,就会发生内存交换
,如果有部分ES使用内存被写到磁盘然后再从磁盘上读取,这个过程会消耗大量时间和资源。如何下设置保证避免内存交换:
-
在elasticsearch.yml 中设置boostrap.mlockall属性为true;
-
设置Xmx和Xms属性值相同,避免JVM改变堆大小,注意内存大小合适,并非越大越好(会导致回收时长变长);
-
修改/etc/security/limits.conf,添加如下内容(假设运行ES的用户是appuser)
appuser - nofile 65536
appuser - memlock unlimited -
修改/etc/pam.d/common-session文件,添加如下内容
session required pam_limits.so
1.3 基准测试
对elasticsearch 指定节点做基准测试,启动命令需要发生变更;
- 命令:bin/elasticsearch --node.bench true
- 基准测试
curl -XPUT 'localhost:9200/_bench/?pretty' -d '{
"name": "firstTest",
"competitors": [{
"name": "post_filter",
"requests": [{
"post_filter": {
"term": {
"link": "hello world"
}
}
}]
},{
"name": "filtered",
"requests": [{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"term": {
"link": "hello world"
}
}
}
}
}]
}
]
}'
返回数据说明:
name:基准测试名称;
competitors:ES将要执行的测试定义;
num_executor_nodes:在测试期间作为查询源的最大Elasticsearch节点数,默认为1个;
iteration:ES应当为每个竞争者重复执行的次数,默认为5次;
concurrency:每次迭代的并发数,默认5个并发现场;
multiplier:在每一次迭代中每个查询重复的次数,默认重复执行1000次;
- 查看基准测试进度
curl -XGET 'localhost:9200/_bench?pretty'
- 中止基准测试
curl -XPOST 'localhost:9200/_bench/abort/firstTest?pretty'
1.4 热点线程检查
假如集群比平时执行缓慢
,使用了大量的CPU资源
,那么可用通过此来进行分析;
- 热点线程API使用
查看热点线程API时,通常使用/_nodes/hot_threads查看集群热点线程,或者/_nodes/{node or nodes}/hot_threads查看端点热点线程,例如:
curl ‘localhost:9200/_nodes/host_threads’
每1s周期查看所有节点处于等待状态的热点线程:
curl ‘localhost:9200/_nodes/host_threads?type=wait&interval=1s’
- 热点线程API响应
0.5% (2.8ms out of 500ms)cpu usage by thread 'elasticsearch[N'Gabtthoth][search][T#10]'
名称:为search的线程,[search]可能会有其他值recovery_stream(回复模块事件)、cache(缓存事件)、merge(索引段合并线程)、index(数据索引线程);
0.5%:统计消耗百分比0.5的CPU时间;
block usage:表示线程处于阻塞状态;
waiting usage:表示线程出游等待状态;
1.5 水平扩展(增加分片)
1.5.1 分片与副本高可用
- 分片和副本数设置与高可用
每个分片都必须设置至少1个副本(一般只设置1个副本),一般来说分片数+副本数>=虚拟机节点数,分片和副本ES内部会自动处理其分布到不同节点,如下图所示8个节点由4个分片和1个副本的分布情况。
1.5.2 物理机-虚拟机-节点高可用
现在很多企业的使用虚拟机,都是由物理机分割而成的,有的一台物理机服务器对应多台虚拟机。因此,为了保证Elasticsearch节点数据的高可用,副本和分片最好不应存在于同一台物理机
上,最好的分布例如下图所示。
为了实现上面节点分布,需要进行如下配置后,这告诉ES不要把分片和它的副本放在具有相同node.server_name属性的节点上:
对于在第1台物理服务器上的所有es节点来说,在elasticsearch.yml文件中设置如下属性:
node.server_name: server1
cluster.routing.allocation.awareness.attributes: server_name
在其他物理服务器上配置类似。
1.5.3 大规模集群设计节点角色
- 指派节点角色,ES节点角色有:
查询聚合节点:分发查询到其他节点,收集和合并结果;
数据节点:接收数据,存储数据;
候选主节点:主节点选举;
默认情况下,Elasticsearch节点兼具查询聚合、数据、候选主节点角色。 - 查询聚合节点elasticsearch.yml配置
node.master: false
node.data: false
- 数据节点elasticsearch.yml配置
node.master: false
node.data: true
- 候选主节点elasticsearch.yml配置
node.master: true
node.data: false
http.enabled: false
通常设置3个候选主节点;
1.6 高负载场景下调优
1.6.1 常规优化建议
– 索引刷新频率
索引刷新频率是指文档需要多长时间文档才能出现在搜索结果中,默认1s。规则:刷新频率越短,查询越慢
,且索引文档的吞吐量越低;在查询实时性要求不是特别高场景下,可适当增大刷新频率时间。
# refresh interval API
curl -XPUT "localhost:9200/index_name" -H 'Content-Type: application/json' -d'{
"settings": {
"refresh_interval": "10s"
}
}'
- 引申出
写
吞吐量调优
index.number_of_replicas: 副本数,越小越好,可降低数据同步一致性时间,从而提高写速度;但会影响查询速度;
index.refresh_interval:刷新频率,越大越好,可降低数据刷新频率,从而提高写速度;但会影响数据查询时效性。
所以针对某些实时性要求不高,夜间批处理场景,可以临时关闭副本数、禁用刷新频率间隔,以提高数据写速度,待任务写完成后再恢复副本数和刷新频率间隔。
#写吞吐量关闭副本和间隔
index.number_of_replicas: "0",
index.refresh_interval: "-1"
–线程池调优
在生产或者压测环境中,ES实例没有100%饱和,但却接收拒绝执行错误,大都因为search 线程设置过小导致程序崩溃, 默认search线程大小=(cpu核数 * 3) / 2 + 1。
Caused by: org.elasticsearch.common.util.concurrent.EsRejectedExecutionException:
rejected execution of org.elasticsearch.search.SearchService$3@4d6f25c2 on EsThreadPoolExecutor
[search, queue capacity = 1000, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@24522e89
[Running, pool size = 13, active threads = 13, queued tasks = 52728, completed tasks = 314227215]]
- 查看线程状态
curl -XGET 'localhost:9200/_cat/thread_pool/
#也可用此api查询
curl -XGET 'localhost:9200/_cat/thread_pool/search?v&h=id,name,active,queue,rejected,completed'
参数依次:节点名称、线程池名称、线程活动状态、线程队列、线程拒绝
- 从ElasticSearch5.0 开始,
无法通过api更改线程池
,需要更改elasticsearch.yml并重启才能生效配置
#允许控制没有线程执行它们的挂起请求队列的初始大小
thread_pool.search.queue_size: 500
#search线程池线程数,默认为核心数乘以5
thread_pool.search.size: 200
#控制queue_size可以调整到的最小数值
thread_pool.search.min_queue_size:10
#控制queue_size可以调整到的最大数值
thread_pool.search.max_queue_size: 1000
#控制在调整队列之前进行测量的操作数。它应该足够大,以便单个操作不会过度偏向计算
thread_pool.search.auto_queue_frame_size: 2000
#控制target_response_time是时间值设置,指示线程池队列中任务目标平均响应耗时;如果任务通常超过此时间,则将调低线程池队列以拒绝任务
thread_pool.search.target_response_time: 6s
–调整段合并过程
原则:如果希望查询更快,就寻求更少的索引段
。更少的段会导致更低的RAM消耗、更快的查询速度、更慢的索引速度
;更多的段会导致更高的RAM消耗,更慢的查询速度和更快的索引速度。
#elasticsearch.yml 配置
index.merge.policy.merge_factory=8 #默认值10,低于10段更少,高于10段更多
indices.store.throttle.max_bytes_per_sec=150MB #合并限流,默认20MB/s,对于SSD硬盘可提高到5-10倍
–合理数据(分片与副本)分布
合理数据分片和副本分布,可有效保障ES节点性能和稳定性,应确保每个节点的负载均衡
,如下图所示:
1.6.2 高查询频率场景优化
建议:总是要考虑优化查询结构
、过滤器的使用
等,可参考Elasticsearch 6.x。
- 节点查询缓存(详解)
有助于查询性能的提升;
--内存限制通过参数indices.queries.cache.size:
indices.queries.cache.size=10% 属性控制缓存的大小,表示给定节点上能够被过利器缓存使用JVM堆内存数量,默认10%,
如果监控缓存逐出比较多,应该考虑增加缓存的大小。
--条数则是通过参数indices.queries.cache.count:
indices.queries.cache.count=1000
--控制是否启用查询缓存。接受true(默认)或 false
index.queries.cache.enabled=true
- 分片请求缓存(详解)
缓存分片查询的缓存,它的目的是缓存聚合、提示词结果和命中数。如果不使用聚合或提示词,那么使用分片数据缓存毫无意义。
index.requests.cache.enable属性设置为ture,开启索引缓存
curl -XPUT 'localhost:9200/index_name/_settings' -d '}
" index.requests.cache.enable":true
}'