社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Elasticsearch

Elasticsearch系列---性能调优最佳实践

1黄鹰 • 3 年前 • 344 次点击  
阅读 27

Elasticsearch系列---性能调优最佳实践

概要

性能调优是系统架构里所有组件必不可少的话题,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目录中看到生成的两个日志文件了。

优化实践建议

基本使用规范

  1. 搜索结果不要返回过大的结果集

过大的结果集会占用大量的IO资源和带宽,速度肯定快不了,Elasticsearch是一个搜索引擎,最理想的搜索是精准查询或次精准查询,最关心的是排在前面的少数结果,而不是所有结果,优化搜索条件,控制搜索结果数量是高性能的前提。

如果真有大批量的数据查询,建议使用scroll api。

  1. 避免超大的document

http.max_context_length的默认值是100mb,如果你一次document写入时,document的内容不能超过100mb,否则es就会拒绝写入。虽然你可以修改此配置,但不建议这么做,es底层的lucene引擎还是有一个2gb的最大限制。

过大的document会占用非常多的资源,从任何方面考虑都不建议,如果业务需求真有非常大的内容,如对书的内容搜索,建议按章节、按段落进行拆分存储。

  1. 避免稀疏的数据

document的设计会从根本上影响索引的性能,稀疏数据是一个典型的不良设计,浪费存储空间,影响读写性能。

下面有一些document结构设计的建议:

  • 避免将没有任何关联性的数据写入同一个索引

没有关联性的数据,意味着数据结构也不相同,硬生生放在同一个索引,会导致index数据非常稀疏,建议是将这些数据放在不同的索引中。

  • 对document的结构进行统一规范化

document的结构、命名尽可能统一规范处理,同样是创建时间字段,避免有的叫timestamp,有的叫create_time,尽可能统一。

  • 对某些field禁用norms和doc_values

如果一个field不需要考虑其相关度分数,那么可以禁用norms,如果不需要对一个field进行排序或者聚合,那么可以禁用doc_values字段。

服务器层级

硬件资源是性能最硬核的部分,硬件好,起点就高。

  1. 用更快的硬件资源

在预算范围内,能用SSD固态硬盘就不要选用机械硬盘;

CPU主频、核数当然是强大到预算上限;

内存单机上限64GB,加机器加到没钱为止;

尽量使用本地存储系统,不要用NFS等网络存储,毕竟硬盘便宜。

  1. 给filesystem cache更多的内存

Elasticsearch的搜索严重依赖于底层的filesystem cache,如果所有的数据都能够存放在filesystem cache中,那么搜索基本上是秒级。

由于实际情况的限制,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。

要达到最佳情况有两个办法:一个是砸钱,买更多机器,加更大内存;另一种是精简document数据,只把需要搜索的field放进es内,filesystem cache就能存下更多的document,可以提高内存的利用率。剩余的其他字段,可以放在redis/mysql/hbase/hapdoop做二级加载。

  1. 禁止swapping交换内存

将swapping禁止掉,如果es jvm内存交换到磁盘,再交换回内存,会造成大量磁盘IO,性能很差。

Elasticsearch层级

  1. index buffer

在高并发写入场景,我们可以将index buffer调大一些,indices.memory.index_buffer_size,这个可以调节大一些,这个值默认是jvm heap的10%,这个index buffer大小,是所有的shard公用的,这个值除以shard数量,算出来平均每个shard可以使用的内存大小,一般建议对于每个shard最多给512mb。

  1. 禁止_all field

_all field会将document中所有field的值都合并在一起进行索引,很占用磁盘空空间,实际上用处却不大,生产环境最好禁用_all field。

  1. 使用best_compression

_source field和其他field很占用磁盘空间,建议对其使用best_compression进行压缩。

  1. 用最小的最合适的数字类型

es支持4种数字类型:byte,short,integer,long。如果最小的类型就合适,那么就用最小的类型,节省磁盘空间。

  1. 禁用不需要的功能

对于需要进行聚合和排序的field,我们才建立正排索引; 对于需要进行检索的field,我们才建立倒排索引; 对于不关心doc分数的field,我们可以禁用掉norm; 对于不需要执行phrase query近似匹配的field,那么可以禁用位置这个属性;

  1. 不要用默认的动态string类型映射

默认的动态string类型映射会将string类型的field同时映射为text类型以及keyword类型,大多数情况我们只需要使用其中一种,剩下的都是浪费磁盘空间,例如,id field这种字段可能只需要keyword,而body field可能只需要text field。

所以是使用keyword和text在设计时就应该区分清楚,而不是全盘保存。

  1. 预热filesystem cache

如果我们重启了Elasticsearch,那么filesystem cache是空的,每次数据查询时再加载数据进filesystem cache,我们可以先对一些数据进行查询,提前将一些常用数据加载到内存,待真实客户使用时,可以直接使用内存数据,响应就很快了。

代码研发层级

  1. 多使用bulk做写入

我们使用Java作为客户端时,写入操作全部利用bulk api来完成。

  1. 使用多线程将数据写入

  2. document使用自动生成的id

手动给document设置一个id,那么es需要每次都去确认一下那个id是否存在,这个过程是比较耗费时间的。如果我们使用自动生成的id,那么es就可以跳过这个步骤,写入性能会更好。

对于关系型数据库中的表id,可以作为es document的一个field存入。

  1. 重视document结构设计

业务研发的重中之重,好的document结构会带来非常优秀的性能表现。

  1. 避免使用script脚本

  2. 充分利用缓存

时间查询时,不要使用now这种函数,应该在客户端把时间转换成规范的格式,再到Elasticsearch里查询,这样能提高缓存的使用率。

小结

本篇介绍了Elasticsearch性能调优的常见实践方法,从服务器、实例再到代码层级,可以作为参考,但性能调优没有约定俗成的方法,需要反复的验证,仅供参考,谢谢

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区 可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术

Java架构社区

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/70636
 
344 次点击