Elasticsearch使用优化之拙见
点击上方“方志朋”,选择“设为星标”
做积极的人,而不是积极废人
Elasticsearch常常作为日志存储和分析的工具,在企业级应用中常常使用。Elasticsearch提供强大的搜索、分析功能,已经是后端技术栈不可缺少的一部分。
在维护ElastciSearch集群的时候,对Elasticsearch进行了一些调优和分析,现整理成文,纯属拙见,如果有不合理之处,欢迎指出探讨。我所使用的Elasticsearch版本为5.x。
文件句柄优化
Elasticsearch有大量的查询数据和插入数据的请求,需要大量文件句柄,centos系统默认的1024个文件句柄。如果文件句柄用完了,这就意味着操作系统会拒绝连接,意味着数据可能丢失,这是灾难性的后果,
不能被接受。登陆Elasticsearch的启动用户,用一下命令查看:
ulimit -a
查看结果:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 127673
max locked memory (kbytes, -l) unlimited
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 2056474
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
上面的文件句柄(open files)的个数为1024,在ElasticSearch大量请求的情况下,这个句柄数量是不够的,可以改成655360。
临时修改可以通过执行以下命令,即可立即生效,但是机器重启后又会失效:
ulimit -n 655360
永久生效,修改/etc/security/limits.conf,需要重启机器生效:
u_es - nofile 655360
上述配置中u_es为启动ElasticSearch的用户,设置了该用户的ElasticSearch的文件句柄为655360、
JVM参数优化
Elasticsearch是运行在JVM上的,对其做JVM参数调优至关重要。最常见的调优是Java内存的分配。下面是JVM的内存模型,具体每块的作用,不在这里阐述。
新生代和老年代分配的内存比例给多大?
Jvm内存分为新生代和老年代。
新生代(或者伊甸园)
新实例化的对象分配的空间。新生代空间通常都非常小,一般在 100 MB–500 MB。新生代也包含两个 幸存 空间。老年代
较老的对象存储的空间。这些对象预计将长期留存并持续上很长一段时间。老生代通常比新生代大很多。
新生代、老生代的垃圾回收都有一个阶段会“stop the world”。在这段时间里,JVM 停止了程序运行,以便对对象进行可达性分析,收集死亡对象。在这个时间停止阶段,一切都不会发生。请求不被服务,ping 不被回应,分片不被分配。整个世界都真的停止了。
对于新生代,这不是什么大问题;那么小的空间意味着 GC 会很快执行完。但是老生代大很多,而这里面一个慢 GC 可能就意味着 1 秒乃至 15 秒的暂停——对于服务器软件来说这是不可接受的。
那一般我们给新生代和老年代分配多大的内存呢?他们的比例是多少呢?
一般来说,老年代和新生代的内存比例为2:1是比较合适的。比如给堆内存分配3G,则新生代分配1G,其余都给老年代。在ElasticSearce的配置文件jvm.options文件配置:
-Xms3g //配置堆初始化大小
-Xmx3g //配置堆的最大内存
-Xmn1g //配置新生代内存。
该分配多大的内存给Elasticesearch?
在使用Elasticesearch的时候,我们对装Elasticesearch的机器进行了升级,从最小的8G内存升级到了16G内存,然后到目前的32G内存。一台机器装一个Elasticesearch节点,我们应该怎么分配机器的内存呢?
官方给出了解决方案,把一半(少于)的内存分配给Luence,另外的内存分配给ElasticSearch.
内存对于 Elasticsearch 来说绝对是重要的,它可以被许多内存数据结构使用来提供更快的操作。但是说到这里, 还有另外一个内存消耗大户 非堆内存 (off-heap):Lucene。
Lucene 被设计为可以利用操作系统底层机制来缓存内存数据结构。Lucene 的段是分别存储到单个文件中的。因为段是不可变的,这些文件也都不会变化,这是对缓存友好的,同时操作系统也会把这些段文件缓存起来,以便更快的访问。
Lucene 的性能取决于和操作系统的相互作用。如果你把所有的内存都分配给 Elasticsearch 的堆内存,那将不会有剩余的内存交给 Lucene。这将严重地影响全文检索的性能。
标准的建议是把 50% 的可用内存作为 Elasticsearch 的堆内存,保留剩下的 50%。当然它也不会被浪费,Lucene 会很乐意利用起余下的内存。
我们实际的解决办法是将机器的一半分给Elasticesearch的堆,栈内存、方法区、常量池、非堆内存占用另外一半。
分配给堆最大内存应该小于 32766 mb(~31.99 gb)
JVM 在内存小于 32 GB 的时候会采用一个内存对象指针压缩技术。
对于 32 位的系统,意味着堆内存大小最大为 4 GB。对于 64 位的系统, 可以使用更大的内存,但是 64 位的指针意味着更大的浪费,因为你的指针本身大了。更糟糕的是, 更大的指针在主内存和各级缓存(例如 LLC,L1 等)之间移动数据的时候,会占用更多的带宽。
Java 使用一个叫作 内存指针压缩(compressed oops)的技术来解决这个问题。它的指针不再表示对象在内存中的精确位置,而是表示 偏移量 。这意味着 32 位的指针可以引用 40 亿个 对象 , 而不是 40 亿个字节。最终, 也就是说堆内存增长到 32 GB 的物理内存,也可以用 32 位的指针表示。
一旦你越过那个神奇的 ~32 GB 的边界,指针就会切回普通对象的指针。每个对象的指针都变长了,就会使用更多的 CPU 内存带宽,也就是说你实际上失去了更多的内存。事实上,当内存到达 40–50 GB 的时候,有效内存才相当于使用内存对象指针压缩技术时候的 32 GB 内存。
这段描述的意思就是说:即便你有足够的内存,也尽量不要 超过 32 GB。因为它浪费了内存,降低了 CPU 的性能,还要让 GC 应对大内存。
关掉swap
内存交换 到磁盘对服务器性能来说是 致命 的。
如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。再想想那么多 10 微秒的操作时延累加起来。不难看出 swapping 对于性能是多么可怕。
用以下命令关掉swap:
sudo swapoff -a
不要碰以下的配置
所有的调整就是为了优化,但是这些调整,你真的不需要理会它。因为它们经常会被乱用,从而造成系统的不稳定或者糟糕的性能,甚至两者都有可能。
线程池配置
许多人 喜欢 调整线程池。无论什么原因,人们都对增加线程数无法抵抗。索引太多了?增加线程!搜索太多了?增加线程!节点空闲率低于 95%?增加线程!
Elasticsearch 默认的线程设置已经是很合理的了。对于所有的线程池(除了 搜索 ),线程个数是根据 CPU 核心数设置的。如果你有 8 个核,你可以同时运行的只有 8 个线程,只分配 8 个线程给任何特定的线程池是有道理的。
搜索线程池设置的大一点,配置为 int(( 核心数 * 3 )/ 2 )+ 1 。
垃圾回收器
Elasticsearch 默认的垃圾回收器( GC )是 CMS。这个垃圾回收器可以和应用并行处理,以便它可以最小化停顿。然而,它有两个 stop-the-world 阶段,处理大内存也有点吃力。
尽管有这些缺点,它还是目前对于像 Elasticsearch 这样低延迟需求软件的最佳垃圾回收器。官方建议使用 CMS。
合理设置最小主节点
minimum_master_nodes 设置及其重要,为了防止集群脑裂,这个参数应该设置为法定个数就是 ( master 候选节点个数 / 2) + 1。
分片均匀,磁盘优化,剔除掉高负载的Master竞选?
笔者在实际生产环境中遇到了有一个节点的负载是其他节点的几倍,从虚拟机监控上看,所有的节点的qps是差不多的。机器的配置是一样的,为什么负载会有如此大的差距?
首先,我们怀疑数据分配不均匀,我们排查了下,没有这种现象。
然后,我们监控到了高负载的节点磁盘IO非常的高,经常达到100%,我们怀疑是那个虚拟机磁盘性能不行。但是我们当时没有更好的磁盘。
我们找到了一个适中的解决办法是将这台高负载的节点剔除Master竞选,即将elasticsearch.yml文件中的node.master改为false然后重启,负载下降了一些。
数据存储天数的优化
存储天数的优化,这个需要根据实际的业务来,下面是删除过期数据的脚本,该脚本来源于https://stackoverflow.com/questions/33430055/removing-old-indices-in-elasticsearch#answer-39746705 ;
#!/bin/bash
searchIndex=logstash-monitor
elastic_url=logging.core.k94.kvk.nl
elastic_port=9200date2stamp () {date --utc --date "$1" +%s
}dateDiff (){case $1 in-s) sec=1; shift;;-m) sec=60; shift;;-h) sec=3600; shift;;-d) sec=86400; shift;;*) sec=86400;;esacdte1=$(date2stamp $1)dte2=$(date2stamp $2)diffSec=$((dte2-dte1))if ((diffSec < 0)); then abs=-1; else abs=1; fiecho $((diffSec/sec*abs))
}for index in $(curl -s "${elastic_url}:${elastic_port}/_cat/indices?v" | grep -E " ${searchIndex}-20[0-9][0-9]\.[0-1][0-9]\.[0-3][0-9]" | awk '{ print $3 }'); dodate=$(echo ${index: -10} | sed 's/\./-/g')cond=$(date +%Y-%m-%d)diff=$(dateDiff -d $date $cond)echo -n "${index} (${diff})"if [ $diff -gt 1 ]; thenecho " / DELETE"# curl -XDELETE "${elastic_url}:${elastic_port}/${index}?pretty"elseecho ""fi
done
然后使用crontab每天定时执行一次这个脚本。
集群分片设置
ES一旦创建好索引后,就无法调整分片的设置,而在ES中,一个分片实际上对应一个lucene 索引,而lucene索引的读写会占用很多的系统资源,因此,分片数不能设置过大;所以,在创建索引时,合理配置分片数是非常重要的。一般来说,我们遵循一些原则:
控制每个分片占用的硬盘容量不超过ES的最大JVM的堆空间设置(一般设置不超过32G,参加上文的JVM设置原则),因此,如果索引的总容量在500G左右,那分片大小在16个左右即可;当然,最好同时考虑原则2。
考虑一下node数量,一般一个节点有时候就是一台物理机,如果分片数过多,大大超过了节点数,很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能会导致数据丢失,集群无法恢复。所以, 一般都设置分片数不超过节点数的3倍。
索引优化
1.修改index_buffer_size 的设置,可以设置成百分数,也可设置成具体的大小,大小可根据集群的规模做不同的设置测试。
indices.memory.index_buffer_size:10%(默认)
indices.memory.min_index_buffer_size:48mb(默认)
indices.memory.max_index_buffer_size
_id字段的使用,应尽可能避免自定义_id, 以避免针对ID的版本管理;建议使用ES的默认ID生成策略或使用数字类型ID做为主键。
_all字段及_source字段的使用,应该注意场景和需要,_all字段包含了所有的索引字段,方便做全文检索,如果无此需求,可以禁用;_source存储了原始的document内容,如果没有获取原始文档数据的需求,可通过设置includes、excludes 属性来定义放入_source的字段。
合理的配置使用index属性,analyzed 和not_analyzed,根据业务需求来控制字段是否分词或不分词。只有 groupby需求的字段,配置时就设置成not_analyzed, 以提高查询或聚类的效率。
查询优化
查询优化,调整filter过滤顺序
如果把过滤效果不明显的条件放在了前面,导致查询出大量不需要的数据,导致查询变慢。
把过滤效果明显的条件提前,按照过滤效果把过滤条件排序
索引时间精度优化
研究Filter的工作原理可以看出,它每次工作都是遍历整个索引的,所以时间粒度越大,对比越快,搜索时间越短,在不影响功能的情况下,时间精度越低越好,有时甚至牺牲一点精度也值得,当然最好的情况是根本不作时间限制。
es重新刷索引,增加冗余的时间字段,精确到天。带有时间范围的查询使用该字段进行查询
查询Fetch Source优化
业务查询语句获取的数据集比较大,并且从source中获取了非必须的字段,导致查询较慢。
举例:只需要从es中查询id这一个字段,却把所有字段查询了出来
预索引数据
利用索引查询数据是最优的方式。例如,如果所有的文档都有 price 字段,并且大多数查询都在一个固定的范围列表中运行范围聚合,那么可以通过将 index 预索引到 index 和使用 terms 聚合来更快地实现聚合。
例如,像下面这样:
PUT index/type/1
{"designation": "spoon","price": 13
}
像这样的查询:
GET index/_search
{"aggs": {"price_ranges": {"range": {"field": "price","ranges": [{ "to": 10 },{ "from": 10, "to": 100 },{ "from": 100 }]}}}
}
文档在索引的时候要使用 price_range ,应该被映射为关键词:
PUT index
{"mappings": {"type": {"properties": {"price_range": {"type": "keyword"}}}}
}PUT index/type/1
{"designation": "spoon","price": 13,"price_range": "10-100"
}
然后这个请求就直接聚合新字段,而不是在 price 字段运行范围查询:
GET index/_search
{"aggs": {"price_ranges": {"terms": {"field": "price_range"}}}
}
总结
总的来说,ElasticSearch的优化,优化可以从以下方面的考虑:
硬件的优化:机器分配,机器配置,机器内存,机器CPU,机器网络,机器磁盘性能
操作系统设置优化:文件句柄优化、swap关闭
ElasticSearch合理分配节点,合理分配参加竞选Master的节点
ElasticSearch的存储的优化,副本数量、索引数量、分片数量
ElasticSearch的使用优化,索引的优化,查询的优化
参考资料
https://www.elastic.co/guide/cn/elasticsearch/guide/current/_monitoring_individual_nodes.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/heap-sizing.html
https://www.fangzhipeng.com/javainterview/2019/04/09/jmm.html
https://www.elastic.co/guide/cn/elasticsearch/guide/current/important-configuration-changes.html
https://stackoverflow.com/questions/33430055/removing-old-indices-in-elasticsearch#answer-39746705
https://zhuanlan.zhihu.com/p/43437056
http://doc.codingdict.com/elasticsearch/497/
热门内容:
为什么说「中台」程序员未来会最值钱?
Java分布式 RPC 框架性能大比拼,Dubbo最差?
如何使用BigDecimal?
面试官:MySQL 表设计要注意什么?
面试官问:平时碰到系统CPU飙高和频繁GC,你会怎么排查?
Java 线程池 ThreadPoolExecutor 八种拒绝策略浅析
Spring Boot 实现定时任务的 4 种方式
Java 程序员常用资源工具集合(建议收藏)
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡
Elasticsearch使用优化之拙见相关推荐
- ElasticSearch性能优化策略【转】
ElasticSearch性能优化主要分为4个方面的优化. 一.服务器部署 二.服务器配置 三.数据结构优化 四.运行期优化 一.服务器部署 1.增加1-2台服务器,用于负载均衡节点 elasticS ...
- 【es】将 elasticsearch 写入速度优化到极限
1.概述 转载:将 elasticsearch 写入速度优化到极限 基于版本: 2.x – 5.x 在 es 的默认设置,是综合考虑数据可靠性,搜索实时性,写入速度等因素的,当你离开默认设置,追求极致 ...
- elasticsearch 性能优化
所有的修改都可以在elasticsearch.yml里面修改,也可以通过api来修改.推荐用api比较灵活 1.不同分片之间的数据同步是一个很大的花费,默认是1s同步,如果我们不要求实时性,我们可以执 ...
- 美团外卖搜索基于Elasticsearch的优化实践
美团外卖搜索工程团队在Elasticsearch的优化实践中,基于Location-Based Service(LBS)业务场景对Elasticsearch的查询性能进行优化.该优化基于Run-Len ...
- Elasticsearch性能优化实战指南
点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 0.背景 在当今世界,各行各业每天都有海量数据产生,为了从这些海量数据中获取想要的分析结果,需 ...
- ElasticSearch 性能优化实战,让你的 ES 飞起来!
点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 ES发布时带有的默认值,可为es的开箱即用带来很好的体验 ...
- 干货!Elasticsearch性能优化实战指南
点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 0.背景 在当今世界,各行各业每天都有海量数据产生,为了 ...
- Elasticsearch 写入优化记录,从3000到8000/s
点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/wmj2004/article/ details/80804411 背景 基于elasticsearch-5.6.0 机器配置: ...
- elasticsearch配置优化
http://m.blog.csdn.net/article/details?id=50330149 节点 Elasticsearch 节点有四种 : master and data--- 默认是这种 ...
最新文章
- hls二次加密 m3u8_HLS实战之Wireshark抓包分析
- 在Rails中撤消脚手架
- Python编程4道练习题
- aes子密钥生成c语言_HBase配置AES加密
- softlockup检测(watchdog)原理(用于检测系统调度是否正常)
- DOD,与cisco三层模型
- reimage repair-打开网页总是自动跳转要你下reimage repair
- Adding Powers
- 网络冗余备份之浮动路由
- css中表格内容从顶部开始,CSS粘性定位固定表格thead部分元素小方法
- 启发式算法(Heuristic Algorithm)
- 获取mp3部分信息的python代码
- Google Play 应用上架流程(2020版)
- Http——超文本传输协议
- Openlayers之地图比例尺控件
- 【个人向】《春物》 小说原文关键段落摘录
- 【UML 建模】在线UML建模工具 ProcessOn 使用具体解释
- android studio运行时报错AVD Nexus_5X_API_P is already running解决办法
- Cocos2d-x 游戏中子弹的设计 (一)
- 计算机学猫叫音乐,抖音学猫叫音乐 抖音学猫叫什么歌