[译]9条关于高性能ElasticSearch的配置建议

原文连接:https://www.loggly.com/blog/nine-tips-configuring-elasticsearch-for-high-performance/node

Loggy使用ES做为其不少核心功能的搜索引擎. 如Jon Gifford在最近的文章ElasticSearch vs Solr中所述, 日志管理系统对搜索引擎有特别需求, 具体以下:bootstrap

  • 对于大规模的数据索引具备可靠的性能及准实时的表现--在咱们场景中,每秒有接近100000条日志记录segmentfault

  • 同时对于大量的搜索处理能维护较高的性能和效率.缓存

在构建咱们的Gen2日志管理服务时, 咱们但愿能设置最优的参数以最大程序的发挥ElasticSearch的索引和搜索性能. 不幸的时, 很难在一个地方收集到完善的ElasticSearch设置文档. 这篇文章总结了咱们学习到的一些知识, 同时能够做为你部署和配置本身的ES应用的一个参考列表.安全

本文档最新更新于09/2016网络

1: 提早规划indices, shards和cluster state的增加趋势

在ES中建立indices和shards很是简单, 但须要记住的是每一个indiex和shard都有相应的资源开销.若是有太多的indices和shards, 单单是对他们管理上的开销就可能大大下降你的ES集群性能, 甚至极端场景下使服务不可用.数据结构

咱们发现对管理系统开销影响最大的因素是cluster state, 包含了集群中每一个索引的mappings信息.曾经某段时间, 咱们单个集群的cluster state信息占用了900MB的空间. 集群虽然还存活着, 但已处于不可用状态.并发

下面咱们经过一些数据来感觉下其中都发生了事情...app

假设你有一个索引, 其mappings大小为50K(在咱们的集群中, 大约有700个字段). 若是你每小时生成一个索引, 那么一天下来将会有24 x 50K的cluster state数据增量, 大约是1.2MB. 若是你的系统中保存了1年的数据, cluster state信息将达到438MB(8760个indices, 53800个shards). 若是天天一个索引的话, cluster state信息会减小到18.25MB(365个indices, 1825个shards). 能够看到,每小时一个索引会把你置于一个彻底不一样的处境.curl

若是你的系统有实时索引数据的需求, 最好先为之作些规划, 并清楚的意识到你的系统中会存储多少cluster state信息以及将包含多少indices和shards. 在部署到生产环境以前, 应该先多作些测试和演练, 避免在凌晨3点因集群不可用而被叫起.

在集群配置方面, 为避免把本身置于险境, 你须要对系统中能容纳的indices和shards数量有全面的掌控.

2: 配置以前,先认识集群拓扑结构

在Loggly, 咱们把ES的master节点和data节点分开部署.如今咱们要说的不是这些细节, 而是强调在你作出正常的配置以前, 先选择正常的拓扑.

另外, 咱们对于索引请求和查询请求也使用了不一样的客户端程序. 这样不但能够为data节点减轻负载, 更重要的是咱们的执行队列能够先提交给本地客户端, 再由其与集群的其余节点交互.

设置节点为master或data节点由如下两个参数的值来决定:

Master node: node.master:true node.data:false
Data node: node.master:false node.data:true
Client node: node.master:false node.data:false

上面的部分比较简单, 下面开始介绍一些须要着重注意的高级属性. 对于大部分系统来讲, ES的默认配置已经足够, 但若是你的使用场景正如咱们常常看到的日志类系统, 请必定不要错过下面的部分.

3: 设置mlockall是提高性能的最有效手段

Linux把它的物理内存划分为不少块, 称为. 而Swapping则是把内存中的一页复制到磁盘上预约义空间的过程, 以释放更多的内存页, 而磁盘上的这部分空间称为交换区. 物理内存和交换区空间的总和称为虚拟内存空间.

交换区并不老是有利的. 由于下内存相比, 磁盘老是慢太多. 一般内存的存储速度在纳秒级, 而磁盘却要毫秒级别. 因此磁盘的访问速度比直接访问内存要慢上万倍. 使用的交换空间越多, 系统会越多, 因此要避免交换区的使用.

mlockall参数容许设置ES节点不换出内存页(只有Linux/Unix系统才有此设置). 在你的yaml文件中, 可经过以下方式设置:

bootstrap.mlockall:true

在5.x版本中, 该参数被bootstrap.memory_lock:true所代替.

默认mlockall的值为false, 意味着ES节点的内存被容许换出. 设置该属性值后, 须要重启ES节点才能生效. 能够经过以下访问进行验证设置是否成功:

curl http://localhost:9200/_nodes/process?pretty

同时要注意, 若是设置了mlockall为true, 要确认经过-DXmx或ES_HEAP_SIZE给你的ES设置了足够的堆空间.

4: 经过discovery.zen控制ES的节点发现管理

Zen discovery是ES集群中节点发现链接的默认机制, 另外还有一些其余的发现机制, 如Azure, EC2和GCE. Zen discovery经过discovery.zen.*的一系列参数进行设置和控制.

在0.x和1.x版本中, 能够设置单播或多播方式, 而且多播是做为ES的默认方式使用的. 若是在这两个版本中想使用单播, 须要设置discovery.zen.ping.multicast.enable为false.

但自从ES 2.0以来, 单播是Zen discovery惟一可用的选择.

首先, 你须要经过discovery.zen.ping.unicast.hosts参数指定一组用于发现和链接节点的hosts. 为了简单, 能够为集群中的每一个节点设置相同的值. 咱们的集群中使用了全部master节点的地址.

discovery.zen.minimum_master_nodes参数用于控制最小的合理master节点数, 使得集群中其余节点可被发现和操做. 一般, 在多于2个节点的集群中建议该参数设置的值不小于2. 另一种计算方式是(master节点数/2 + 1).

Data节点和master节点以前有两种检测方式:

  • master向全部其余节点发起ping请求, 以确认该节点是否存活

  • 其余的节点向master节点发现ping请求,以确认master是否存活,并决定是否须要开始新一轮的选举

节点检测过程由discovery.zen.fd.ping_timeout参数设置, 默认值为30s, 决定了一个发起ping请求的节点的响应等待时间. 若是你的集群带宽不足或网络拥堵, 则须要合理的从新调整该参数. 若是网络较差,该参数要相应的设置大一些, 值越大, 节点发现的失败的风险也就越低.

Loggly的discovery.zen参数设置以下:

discovery.zen.df.ping_timeout: 30s
discovery.zen.mininum_master_nodes: 2
discovery.zen.ping.unicast.hosts: ["esmaster01", "esmaster02", "esmaster03"]

就是说30s内须要有节点检测响应返回(经过discovery.zen.df.ping_timeout设置的).另外,其余节点至少要检测到2个master节点(咱们总共有3个master节点), 第三个参数是说咱们的单播主机分别为esmaster01, esmaster02和esmaster03.

5: 提防"DELETE_all"

ES的DELETE API容许你经过一个请求(使用通配符或_all)删除全部的索引数据, 意识到这一点很是重要.以下:

curl -XDELETE 'http://localhost:9200/*/'
curl -XDELETE 'http://localhost:9200/_all'

虽然这个功能很强大,却也极为危险,特别是在生产环境. 在咱们全部的集群中, 咱们都经过action.destructive_requires_name:true参数禁用了该删除功能.

这个参数由ES 1.0并入, 并替换掉了0.90版本中使用的action.disable_delete_all_indices参数.

6: 使用Doc Values

在ES2.0及以上版本中, Doc Values是默认使用的.而在较早的版本中则须要显示指定.Doc Values经过少许额外的索引和磁盘开销, 提供了比在normal字段上更高效的排序和聚合操做.本质上, Doc Values经过把ES转变为列式存储, 进而使得ES大量的分词特性比预想的更高效.

为了深刻理解Doc Values带来的好处, 下面将把Doc Values与normal字段进行对比.

当在normal字段上进行排序或聚合操做时, 将致使大量的fielddata cache.由于当字段第一次被缓存时, ES须要为该字段每一个可能的取值分配大量的堆空间, 并从每一个文档中获取字段值数据. 由于这个过程可能须要从磁盘中读取数据, 由于将会十分耗时.一旦数据缓存完成, 之后再对该字段值的使用都会使用先前缓存的数据, 因此速度也会更快.但当有过多的字段被载入到缓存中时, 就会触发缓存淘汰机制, 一些字段将被汰出, 相应的再次使用被汰出的字段时, 就是又一次的耗时载入过程. 为了高效, 你可能想减小或下降缓存汰出, 这意味着你要减小或限制将被缓存的字段数量.

与之不一样, Doc Values使用基于磁盘的数据结构, 并映射到进程的内存空间, 从而减小对堆空间的占用, 并具备与fielddata cache相匹敌的性能. 虽然在数据第一次从硬盘读取并载入时依然会有起始开销, 然而这一些都有操做系统的文件系统缓存进行处理, 因此只有你真正须要的数据才会被读入.

简而言之, Doc Values减小了堆空间使用(相应的下降了GC影响), 并经过文件系统缓存减小读取的数据, 从而提升了总体性能.

7: ES shard分配相关的参数设置

shard分配就是把shard分散到不一样节点的过程,能够发生在初始化备份阶段, 副本分配阶段或者节点再平衡过程当中.也就是说它发生在任何节点增长或移除的过程当中.

参数cluster.routing.allocation.cluster_concurrent_rebalance决定了在shard再平衡过程当中容许并发的shard数.合适的设置由你使用的硬件性能决定, 如集群节点使用的CPU核数, IO性能等.若是参数设置的不合理,将会对ES索引过程的性能带来必定的影响.

cluster.routing.allocation.cluster_concurrent_rebalance:2

ES默认设置的值为2, 也就是说在任什么时候候最多只容许同时移动2个shards的数据.设置一个不过高的合理数值老是值得的,虽然shard再平衡的并发数受到制约, 但却不会对索引数据形成影响.

另一个值得一提的参数是cluster.routing.allocation.disk.threshold_enabled.若是这个参数设置为true, 则在shard分配过程当中为shard预留空闲的磁盘空间, 相反若是设置为false,则分配到该节点上的shard数据的将来增长将受到限制--没有足够的空间.

当threshold_enabled设置为true, 有两个相应的指标能够配置:low 和 high.

  • low 定义了当磁盘使用量超过该指标后,ES将再也不为该节点分配shard, 默认值为85%

  • high 定义了当磁盘使用量超过该指标后,将有shard从该节点中移出, 默认值为90%

这两个参数便可按已使用量的百分比定义(例如,80%是说使用了80%的磁盘,尚有20%空闲), 也能够按最小可用磁盘空间定义(例如,20GB是说该节点尚有20GB空闲空间).

若是你有大量的小shards, ES使用的默认值可能会有些保守. 例如你有1TB的存储空间,而每一个shard的大小仅为10GB, 理论上该节点能容纳100个数据shards.若是采用上面的默认设置, 在ES认为节点饱和前, 你最多只能存储80个shards.

因此为了找出一个合理设置, 你须要仔细观察在shard生命周期中的容量变化, 同时为之预留必定的安全空间.在上面的例子中, 假若有5个数据shards, 则须要确认在任什么时候候都要有50GB的可用空间(不是空闲空间, 是5个shards将占用的总空间).对于1TB的设备, 若是不考虑安全空间, low的值可设置为95%. 然而乘以50%的安全系数, 则须要至少预留75GB的空闲空间, 相应的合理的low值应为92.5%.

8: 合理的恢复设置帮你提高节点重启速度

ES提供了几个属性用于提升集群恢复速度,缩短节点重启时间.合理的取值依赖于你的硬件能力(硬盘和网络速度一般会是瓶颈), 因此能给出的最好的建议就是尝试,尝试,再尝试.

  • 控制单个节点并发恢复数据的shard数:

    cluster.routing.allocation.node_concurrent_recoveries

    shard数据恢复是一个IO密集型操做, 所以须要根据实际情形设置参数.在ES 5.x版本中, 这个参数分拆成两个新的设置:

cluster.routing.allocation.node_concurrent_incoming_recoveries
cluster.routing.allocation.node_concurrent_outgoing_recoveries
  • 控制单个节点上初始的主shard并发数:

    cluster.routing.allocation.node_initial_primaries_recoveries
  • 控制一个shard恢复数据时并行打开的数据流个数:

    indices.recovery.concurrent_streams
  • 与数据流紧密相关的是可用的带宽限制:

    indices.recovery.max_bytes_per_sec

    实际使用的硬件配置直接决定了以上几个参数的最优值设置.使用SSD硬盘以及高速的(10G)以太网结构和使用机械硬盘以及1G的以太网结构将有巨大的差异.

只有在集群重启的时候,才会使用以上数据恢复相关的参数设置.

9: 合理的线程池设置避免数据丢失

为了提升节点内的线程管理, ES维护了多个线程池.

在Loggly, 咱们在使用_bulk操做来处理索引请求时发现, 设置合适的threadpool.bulk.queue_size对避免_bulk重试以及由其可能引发的数据丢失相当重要.

threadpool.bulk.queue_size: 5000

上面的参数用于设置bulk的队列长度, 即当节点的每一个shard在处理bulk请求时, 若是无可用线程时, 能为每一个shard排队等待的请求数量.这个参数应该与你的bulk请求负载相匹配, 若是设置太小, 而bulk请求较多时, ES会返回一个RemoteTransportException.

如上所述, bulk请求涉及到的每一个shard的数据都在这个队列里, 所以合理的设置是bulk的并发数乘以这些请求相关的shard数. 好比说: 单个bulk请求包含的数据分布在10个shards上, 即使只有一次bulk请求, 你也要有一个至少长度为10的队列设置.话说回来, 若是设置过大则会消耗更多的JVM堆空间(同时意味你正提交的数据量可能超出你实际能索引的能力), 然而却能减化你的客户端处理逻辑.

要么设置一个相对合适的较大的队列值, 要么在你的代码中合理的处理掉RemoteTransportException. 若是处理不当, 则会面临数据丢失的风险. 下面的异常模仿的是队列长度为10,而并发发起了超过10个bulk请求的场景:

RemoteTransportException[[<Bantam>][inet[/192.168.76.1:9300]][bulk/shard]]; nested: EsRejectedExecutionException[rejected execution (queue capacity 10) on org.elasticsearch.action.support.replication.TransportShardReplicationOperationAction$AsyncShardOperationAction$1@13fe9be];
相关文章
相关标签/搜索