共计 7593 个字符,预计需要花费 19 分钟才能阅读完成。
原文: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
:节点确定退出到集群中,向主节点发送退出申请的超时工夫,默认为 3 sdiscovery.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 的害处:
- 造成集群元数据始终变更,导致集群不稳固;
- 可能造成数据类型与理论类型不统一;
- 对于一些异样字段或者是扫描类的字段,也会频繁的批改 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
获取材料::