性能调优是系统架构里所有组件必不可少的话题,Elasticsearch也不例外,虽说Elasticsearch内的默认配置已经非常优秀,但这不表示它就是完美的,必要的一些实践我们还是需要了解一下。
慢查询日志是性能诊断的重要利器,常规操作是设置慢查询的阀值,然后运维童鞋每天对慢日志进行例行巡查,有特别慢的查询,立即报备事件处理,其余的定期将慢日志的top n取出来进行优化。
慢日志的配置在elasticsearch 6.3.1版本下是通过命令配置的,读操作和写操作可以单独设置,阀值的定义可根据实际的需求和性能指标,有人觉得5秒慢,有人觉得3秒就不可接受,我们以3秒为例:
PUT /_all/_settings { "index.search.slowlog.threshold.query.warn":"3s", "index.search.slowlog.threshold.query.info":"2s", "index.search.slowlog.threshold.query.debug":"1s", "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", "index.indexing.slowlog.threshold.index.warn":"3s", "index.indexing.slowlog.threshold.index.info":"2s", "index.indexing.slowlog.threshold.index.debug":"1s", "index.indexing.slowlog.threshold.index.trace":"500ms", "index.indexing.slowlog.level":"info", "index.indexing.slowlog.source":"1000" }
这三段分别表示query查询、fetch查询和index写入三类操作的慢日志输出阀值,_all表示对所有索引生效,也可以针对具体的索引。
同时在log4j2.properties配置文件中增加如下配置:
# 查询操作慢日志输出 appender.index_search_slowlog_rolling.type = RollingFile appender.index_search_slowlog_rolling.name = index_search_slowlog_rolling appender.index_search_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog.log appender.index_search_slowlog_rolling.layout.type = PatternLayout appender.index_search_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %.10000m%n appender.index_search_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_search_slowlog-%d{yyyy-MM-dd}.log appender.index_search_slowlog_rolling.policies.type = Policies appender.index_search_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.index_search_slowlog_rolling.policies.time.interval = 1 appender.index_search_slowlog_rolling.policies.time.modulate = true logger.index_search_slowlog_rolling.name = index.search.slowlog logger.index_search_slowlog_rolling.level = trace logger.index_search_slowlog_rolling.appenderRef.index_search_slowlog_rolling.ref = index_search_slowlog_rolling logger.index_search_slowlog_rolling.additivity = false # 索引操作慢日志输出 appender.index_indexing_slowlog_rolling.type = RollingFile appender.index_indexing_slowlog_rolling.name = index_indexing_slowlog_rolling appender.index_indexing_slowlog_rolling.fileName = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog.log appender.index_indexing_slowlog_rolling.layout.type = PatternLayout appender.index_indexing_slowlog_rolling.layout.pattern = [%d{ISO8601}][%-5p][%-25c] %marker%.10000m%n appender.index_indexing_slowlog_rolling.filePattern = ${sys:es.logs.base_path}${sys:file.separator}${sys:es.logs.cluster_name}_index_indexing_slowlog-%d{yyyy-MM-dd}.log appender.index_indexing_slowlog_rolling.policies.type = Policies appender.index_indexing_slowlog_rolling.policies.time.type = TimeBasedTriggeringPolicy appender.index_indexing_slowlog_rolling.policies.time.interval = 1 appender.index_indexing_slowlog_rolling.policies.time.modulate = true logger.index_indexing_slowlog.name = index.indexing.slowlog.index logger.index_indexing_slowlog.level = trace logger.index_indexing_slowlog.appenderRef.index_indexing_slowlog_rolling.ref = index_indexing_slowlog_rolling logger.index_indexing_slowlog.additivity = false
重启elasticsearch实例后,就能在/home/esuser/esdata/log
目录中看到生成的两个日志文件了。
过大的结果集会占用大量的IO资源和带宽,速度肯定快不了,Elasticsearch是一个搜索引擎,最理想的搜索是精准查询或次精准查询,最关心的是排在前面的少数结果,而不是所有结果,优化搜索条件,控制搜索结果数量是高性能的前提。
如果真有大批量的数据查询,建议使用scroll api。
http.max_context_length的默认值是100mb,如果你一次document写入时,document的内容不能超过100mb,否则es就会拒绝写入。虽然你可以修改此配置,但不建议这么做,es底层的lucene引擎还是有一个2gb的最大限制。
过大的document会占用非常多的资源,从任何方面考虑都不建议,如果业务需求真有非常大的内容,如对书的内容搜索,建议按章节、按段落进行拆分存储。
document的设计会从根本上影响索引的性能,稀疏数据是一个典型的不良设计,浪费存储空间,影响读写性能。
下面有一些document结构设计的建议:
没有关联性的数据,意味着数据结构也不相同,硬生生放在同一个索引,会导致index数据非常稀疏,建议是将这些数据放在不同的索引中。
document的结构、命名尽可能统一规范处理,同样是创建时间字段,避免有的叫timestamp,有的叫create_time,尽可能统一。
如果一个field不需要考虑其相关度分数,那么可以禁用norms,如果不需要对一个field进行排序或者聚合,那么可以禁用doc_values字段。
硬件资源是性能最硬核的部分,硬件好,起点就高。
在预算范围内,能用SSD固态硬盘就不要选用机械硬盘;
CPU主频、核数当然是强大到预算上限;
内存单机上限64GB,加机器加到没钱为止;
尽量使用本地存储系统,不要用NFS等网络存储,毕竟硬盘便宜。
Elasticsearch的搜索严重依赖于底层的filesystem cache,如果所有的数据都能够存放在filesystem cache中,那么搜索基本上是秒级。
由于实际情况的限制,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。
要达到最佳情况有两个办法:一个是砸钱,买更多机器,加更大内存;另一种是精简document数据,只把需要搜索的field放进es内,filesystem cache就能存下更多的document,可以提高内存的利用率。剩余的其他字段,可以放在redis/mysql/hbase/hapdoop做二级加载。
将swapping禁止掉,如果es jvm内存交换到磁盘,再交换回内存,会造成大量磁盘IO,性能很差。
在高并发写入场景,我们可以将index buffer调大一些,indices.memory.index_buffer_size,这个可以调节大一些,这个值默认是jvm heap的10%,这个index buffer大小,是所有的shard公用的,这个值除以shard数量,算出来平均每个shard可以使用的内存大小,一般建议对于每个shard最多给512mb。
_all field会将document中所有field的值都合并在一起进行索引,很占用磁盘空空间,实际上用处却不大,生产环境最好禁用_all field。
_source field和其他field很占用磁盘空间,建议对其使用best_compression进行压缩。
es支持4种数字类型:byte,short,integer,long。如果最小的类型就合适,那么就用最小的类型,节省磁盘空间。
本文系作者在时代Java发表,未经许可,不得转载。
如有侵权,请联系nowjava@qq.com删除。