原文:http://elasticsearch.cn/artic...

因为总是看到很多同学在说elasticsearch性能不够好,集群不够稳固,询问对于elasticsearch的调优,然而每次都是一个个点的独自讲,很多时候都是case by case的解答,明天简略梳理下日常的elasticsearch应用调优,以下仅为本人日常经验之谈,如有疏漏,还请大家帮忙斧正。

一、配置文件调优

elasticsearch.yml

内存锁定

bootstrap.memory_lock:true 容许 JVM 锁住内存,禁止操作系统替换进来。

zen.discovery

Elasticsearch 默认被配置为应用单播发现,以避免节点无心中退出集群。组播发现应该永远不被应用在生产环境了,否则你失去的后果就是一个节点意外的退出到了你的生产环境,仅仅是因为他们收到了一个谬误的组播信号。 ES是一个P2P类型的分布式系统,应用gossip协定,集群的任意申请都能够发送到集群的任一节点,而后es外部会找到须要转发的节点,并且与之进行通信。 在es1.x的版本,es默认是开启组播,启动es之后,能够疾速将局域网内集群名称,默认端口的雷同实例退出到一个大的集群,后续再es2.x之后,都调整成了单播,防止平安问题和网络风暴;

单播discovery.zen.ping.unicast.hosts,倡议写入集群内所有的节点及端口,如果新实例退出集群,新实例只须要写入以后集群的实例,即可主动退出到以后集群,之后再解决原实例的配置即可,新实例退出集群,不须要重启原有实例; 节点zen相干配置: discovery.zen.ping_timeout:判断master选举过程中,发现其余node存活的超时设置,次要影响选举的耗时,参数仅在退出或者选举 master 主节点的时候才起作用discovery.zen.join_timeout:节点确定退出到集群中,向主节点发送退出申请的超时工夫,默认为3sdiscovery.zen.minimum_master_nodes:参加master选举的最小节点数,当集群可能被选为master的节点数量小于最小数量时,集群将无奈失常选举。

故障检测( fault detection )

两种状况下回进行故障检测,第一种是由master向集群的所有其余节点发动ping,验证节点是否处于活动状态;第二种是:集群每个节点向master发动ping,判断master是否存活,是否须要发动选举。 故障检测须要配置以下设置应用 形如: discovery.zen.fd.ping_interval 节点被ping的频率,默认为1s。 discovery.zen.fd.ping_timeout 期待ping响应的工夫,默认为 30s,运行的集群中,master 检测所有节点,以及节点检测 master 是否失常。 discovery.zen.fd.ping_retries ping失败/超时多少导致节点被视为失败,默认为3。

https://www.elastic.co/guide/...
队列数量

不倡议自觉加大es的队列数量,如果是偶发的因为数据突增,导致队列阻塞,加大队列size能够应用内存来缓存数据,如果是持续性的数据阻塞在队列,加大队列size除了加大内存占用,并不能无效进步数据写入速率,反而可能加大es宕机时候,在内存中可能失落的上数据量。 哪些状况下,加大队列size呢?GET /_cat/thread_pool,察看api中返回的queue和rejected,如果的确存在队列回绝或者是继续的queue,能够酌情调整队列size。

https://www.elastic.co/guide/...
内存应用

设置indices的内存熔断相干参数,依据理论状况进行调整,避免写入或查问压力过高导致OOM, indices.breaker.total.limit: 50%,集群级别的断路器,默认为jvm堆的70%; indices.breaker.request.limit: 10%,单个request的断路器限度,默认为jvm堆的60%; indices.breaker.fielddata.limit: 10%,fielddata breaker限度,默认为jvm堆的60%。

https://www.elastic.co/guide/...

依据理论状况调整查问占用cache,防止查问cache占用过多的jvm内存,参数为动态的,须要在每个数据节点配置。 indices.queries.cache.size: 5%,管制过滤器缓存的内存大小,默认为10%。承受百分比值,5%或者准确值,例如512mb。

https://www.elastic.co/guide/...
创立shard

如果集群规模较大,能够阻止新建shard时扫描集群内全副shard的元数据,晋升shard调配速度。 cluster.routing.allocation.disk.include_relocations: false,默认为true。

https://www.elastic.co/guide/...

二、零碎层面调优

jdk版本

以后依据官网倡议,抉择匹配的jdk版本;

jdk内存配置

首先,-Xms和-Xmx设置为雷同的值,防止在运行过程中再进行内存调配,同时,如果零碎内存小于64G,倡议设置略小于机器内存的一半,残余留给零碎应用。 同时,jvm heap倡议不要超过32G(不同jdk版本具体的值会略有不同),否则jvm会因为内存指针压缩导致内存节约,详见:

https://www.elastic.co/guide/...

替换分区

敞开替换分区,避免内存产生替换导致性能降落(局部状况下,宁死勿慢) swapoff -a

文件句柄

Lucene 应用了 大量的 文件。 同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也应用了大量的套接字,所有这所有都须要足够的文件描述符,默认状况下,linux默认运行单个过程关上1024个文件句柄,这显然是不够的,故须要加大文件句柄数 ulimit -n 65536

https://www.elastic.co/guide/...

mmap

Elasticsearch 对各种文件混合应用了 NioFs( 注:非阻塞文件系统)和 MMapFs ( 注:内存映射文件系统)。请确保你配置的最大映射数量,以便有足够的虚拟内存可用于 mmapped 文件。这能够临时设置: sysctl -w vm.max_map_count=262144 或者你能够在 /etc/sysctl.conf 通过批改 vm.max_map_count 永恒设置它。

https://www.elastic.co/guide/...

磁盘

如果你正在应用 SSDs,确保你的零碎 I/O 调度程序是配置正确的。 当你向硬盘写数据,I/O 调度程序决定何时把数据理论发送到硬盘。 大多数默认 nix 发行版下的调度程序都叫做 cfq(齐全偏心队列)。但它是为旋转介质优化的: 机械硬盘的固有个性意味着它写入数据到基于物理布局的硬盘会更高效。 这对 SSD 来说是低效的,只管这里没有波及到机械硬盘。然而,deadline 或者 noop 应该被应用。deadline 调度程序基于写入等待时间进行优化, noop 只是一个简略的 FIFO 队列。 echo noop > /sys/block/sd/queue/scheduler

磁盘挂载

mount -o noatime,data=writeback,barrier=0,nobh /dev/sd* /esdata* 其中,noatime,禁止记录拜访工夫戳;data=writeback,不记录journal;barrier=0,因为敞开了journal,所以同步敞开barrier; nobh,敞开buffer_head,避免内核影响数据IO

磁盘其余注意事项

应用 RAID 0。条带化 RAID 会进步磁盘I/O,代价显然就是当一块硬盘故障时整个就故障了,不要应用镜像或者奇偶校验 RAID 因为正本曾经提供了这个性能。 另外,应用多块硬盘,并容许 Elasticsearch 通过多个 path.data 目录配置把数据条带化调配到它们下面。 不要应用近程挂载的存储,比方 NFS 或者 SMB/CIFS。这个引入的提早对性能来说齐全是南辕北辙的。

三、elasticsearch应用形式调优

当elasticsearch自身的配置没有显著的问题之后,发现es应用还是十分慢,这个时候,就须要咱们去定位es自身的问题了,首先祭出定位问题的第一个命令:

hot_threads

GET /_nodes/hot_threads&interval=30s

抓取30s的节点上占用资源的热线程,并通过排查占用资源最多的TOP线程来判断对应的资源耗费是否失常,个别状况下,bulk,search类的线程占用资源都可能是业务造成的,然而如果是merge线程占用了大量的资源,就应该思考是不是创立index或者刷磁盘距离太小,批量写入size太小造成的。

https://www.elastic.co/guide/...

pending_tasks

GET /_cluster/pending_tasks

有一些工作只能由主节点去解决,比方创立一个新的 索引或者在集群中挪动分片,因为一个集群中只能有一个主节点,所以只有这一master节点能够解决集群级别的元数据变动。在99.9999%的工夫里,这不会有什么问题,元数据变动的队列基本上放弃为零。在一些常见的集群里,元数据变动的次数比主节点能解决的还快,这会导致期待中的操作会累积成队列。这个时候能够通过pending_tasks api剖析以后什么操作阻塞了es的队列,比方,集群异样时,会有大量的shard在recovery,如果集群在大量创立新字段,会呈现大量的put_mappings的操作,所以失常状况下,须要禁用动静mapping。

https://www.elastic.co/guide/...

字段存储

以后es次要有doc_values,fielddata,storefield三种类型,大部分状况下,并不需要三种类型都存储,可依据理论场景进行调整: 以后用得最多的就是doc_values,列存储,对于不须要进行分词的字段,都能够开启doc_values来进行存储(且只保留keyword字段),节约内存,当然,开启doc_values会对查问性能有肯定的影响,然而,这个性能损耗是比拟小的,而且是值得的;

fielddata构建和治理 100% 在内存中,常驻于 JVM 内存堆,所以可用于疾速查问,然而这也意味着它实质上是不可扩大的,有很多边缘状况下要提防,如果对于字段没有剖析需要,能够敞开fielddata;

storefield次要用于_source字段,默认状况下,数据在写入es的时候,es会将doc数据存储为_source字段,查问时能够通过_source字段疾速获取doc的原始构造,如果没有update,reindex等需要,能够将_source字段disable;

_all,ES在6.x以前的版本,默认将写入的字段拼接成一个大的字符串,并对该字段进行分词,用于反对整个doc的全文检索,在晓得doc字段名称的状况下,倡议敞开掉该字段,节约存储空间,也防止不带字段key的全文检索;

norms:搜寻时进行评分,日志场景个别不须要评分,倡议敞开;

tranlog

Elasticsearch 2.0之后为了保障不丢数据,每次 index、bulk、delete、update 实现的时候,肯定触发刷新 translog 到磁盘上,才给申请返回 200 OK。这个扭转在进步数据安全性的同时当然也升高了一点性能。 如果你不在意这点可能性,还是心愿性能优先,能够在 index template 里设置如下参数:

{    "index.translog.durability": "async"}

index.translog.sync_interval:对于一些大容量的偶然失落几秒数据问题也并不重大的集群,应用异步的 fsync 还是比拟无益的。比方,写入的数据被缓存到内存中,再每5秒执行一次 fsync ,默认为5s。小于的值100ms是不容许的。 index.translog.flush_threshold_size:translog存储尚未平安保留在Lucene中的所有操作。尽管这些操作可用于读取,但如果要敞开并且必须复原,则须要从新编制索引。此设置管制这些操作的最大总大小,以避免复原工夫过长。达到设置的最大size后,将产生刷新,生成新的Lucene提交点,默认为512mb。

refresh_interval

执行刷新操作的频率,这会使索引的最近更改对搜寻可见,默认为1s,能够设置-1为禁用刷新,对于写入速率要求较高的场景,能够适当的加大对应的时长,减小磁盘io和segment的生成;

禁止动静mapping

动静mapping的害处:

  1. 造成集群元数据始终变更,导致集群不稳固;
  2. 可能造成数据类型与理论类型不统一;
  3. 对于一些异样字段或者是扫描类的字段,也会频繁的批改mapping,导致业务不可控。

动静mapping配置的可选值及含意如下: true:反对动静扩大,新增数据有新的字段属性时,主动增加对于的mapping,数据写入胜利 false:不反对动静扩大,新增数据有新的字段属性时,间接疏忽,数据写入胜利 strict:不反对动静扩大,新增数据有新的字段时,报错,数据写入失败

批量写入

批量申请显然会大大晋升写入速率,且这个速率是能够量化的,官网倡议每次批量的数据物理字节数5-15MB是一个比拟不错的终点,留神这里说的是物理字节数大小。文档计数对批量大小来说不是一个好指标。比如说,如果你每次批量索引 1000 个文档,记住上面的事实: 1000 个 1 KB 大小的文档加起来是 1 MB 大。 1000 个 100 KB 大小的文档加起来是 100 MB 大。 这可是完完全全不一样的批量大小了。批量申请须要在协调节点上加载进内存,所以批量申请的物理大小比文档计数重要得多。 从 5–15 MB 开始测试批量申请大小,迟缓减少这个数字,直到你看不到性能晋升为止。而后开始减少你的批量写入的并发度(多线程等等方法)。 用iostat 、 top 和 ps 等工具监控你的节点,察看资源什么时候达到瓶颈。如果你开始收到 EsRejectedExecutionException ,你的集群没方法再持续了:至多有一种资源到瓶颈了。或者缩小并发数,或者提供更多的受限资源(比方从机械磁盘换成 SSD),或者增加更多节点。

索引和shard

es的索引,shard都会有对应的元数据,且因为es的元数据都是保留在master节点,且元数据的更新是要hang住集群向所有节点同步的,当es的新建字段或者新建索引的时候,都会要获取集群元数据,并对元数据进行变更及同步,此时会影响集群的响应,所以须要关注集群的index和shard数量,倡议如下: 1.应用shrink和rollover api,绝对生成适合的数据shard数; 2.依据数据量级及对应的性能需求,抉择创立index的名称,形如:按月生成索引:test-YYYYMM,按天生成索引:test-YYYYMMDD; 3.管制单个shard的size,失常状况下,日志场景,倡议单个shard不大于50GB,线上业务场景,倡议单个shard不超过20GB;

segment merge

段合并的计算量宏大, 而且还要吃掉大量磁盘 I/O。合并在后盾定期操作,因为他们可能要很长时间能力实现,尤其是比拟大的段。这个通常来说都没问题,因为大规模段合并的概率是很小的。 如果发现merge占用了大量的资源,能够设置: index.merge.scheduler.max_thread_count: 1 特地是机械磁盘在并发 I/O 反对方面比拟差,所以咱们须要升高每个索引并发拜访磁盘的线程数。这个设置容许 max_thread_count + 2 个线程同时进行磁盘操作,也就是设置为 1 容许三个线程。 对于 SSD,你能够疏忽这个设置,默认是 Math.min(3, Runtime.getRuntime().availableProcessors() / 2) ,对 SSD 来说运行的很好。 业务低峰期通过force_merge强制合并segment,升高segment的数量,减小内存耗费; 敞开冷索引,业务须要的时候再进行开启,如果始终不应用的索引,能够定期删除,或者备份到hadoop集群;

主动生成_id

当写入端应用特定的id将数据写入es时,es会去查看对应的index下是否存在雷同的id,这个操作会随着文档数量的减少而耗费越来越大,所以如果业务上没有强需要,倡议应用es主动生成的id,放慢写入速率。

routing

对于数据量较大的业务查问场景,es侧个别会创立多个shard,并将shard调配到集群中的多个实例来摊派压力,失常状况下,一个查问会遍历查问所有的shard,而后将查问到的后果进行merge之后,再返回给查问端。此时,写入的时候设置routing,能够防止每次查问都遍历全量shard,而是查问的时候也指定对应的routingkey,这种状况下,es会只去查问对应的shard,能够大幅度降低合并数据和调度全量shard的开销。

应用alias

生产提供服务的索引,切记应用别名提供服务,而不是间接裸露索引名称,防止后续因为业务变更或者索引数据须要reindex等状况造成业务中断。

防止宽表

在索引中定义太多字段是一种可能导致映射爆炸的状况,这可能导致内存不足谬误和难以复原的状况,这个问题可能比预期更常见,index.mapping.total_fields.limit ,默认值是1000

防止稠密索引

因为索引稠密之后,对应的相邻文档id的delta值会很大,lucene基于文档id做delta编码压缩导致压缩率升高,从而导致索引文件增大,同时,es的keyword,数组类型采纳doc_values构造,每个文档都会占用肯定的空间,即便字段是空值,所以稠密索引会造成磁盘size增大,导致查问和写入效率升高。

学习材料分享

12 套 微服务、Spring Boot、Spring Cloud 核心技术材料,这是局部材料目录:

  • Spring Security 认证与受权
  • Spring Boot 我的项目实战(中小型互联网公司后盾服务架构与运维架构)
  • Spring Boot 我的项目实战(企业权限治理我的项目))
  • Spring Cloud 微服务架构我的项目实战(分布式事务解决方案)
  • ...

    公众号后盾回复arch028获取材料::