ElasticSearch 最佳实践

Author Avatar
Joway Wang 5月 28, 2017
  • 在其它设备中阅读本文章

Elasticsearch 是一个需要不停调参数的庞然大物 , 从其自身的设置到JVM层面, 有着无数的参数需要根据业务的变化进行调整。最近采用3台 AWS r3.2xlarge , 32GB, 4核, 构建了一套日均日志量过亿的EFK套件。经过不停地查阅文档进行调整优化 , 目前日常CPU占用只在30% , 大部分 Kibana 内的查询都能在 5s ~ 15s 内完成。

下面记录了一些实践过程中积累的经验。

硬件

CPU

  1. 多核胜过高性能单核CPU
  2. 实践中发现, 在高写入低查询的场景下, 日常状态时 , CPU 还能基本应付, 一旦进行 kibana 上的查询或者 force merge 时, CPU 会瞬间飙高, 从而导致写入变慢, 进而引发需要很长一段实践 cpu 才能降下来。

Mem

  1. Elasticsearch 需要使用大量的堆内存, 而 Lucene 则也需要消耗大量 非堆内存 (off-heap)。推荐给 es 设置本机内存的一半, 如32G 内存的机器上, 设置 -Xmx16g -Xms16g 剩下的内存会被 Lucene 占用。
  2. 如果你不需要对分词字符串做聚合计算(例如,不需要 fielddata )可以考虑降低堆内存。堆内存越小,Elasticsearch(更快的 GC)和 Lucene(更多的内存用于缓存)的性能越好。
  3. 由于 JVM 的一些机制 , 内存并不是越大越好, 推荐最大只设置到 31 GB 。
  4. 禁用 swap sudo swapoff -a

配置

PS: 应该尽可能使用 ansible 这类工具去管理集群 , 否则集群内机器的状态不一致将是一场噩梦。

JVM

  • 不轻易丢改 jvm 参数 , 现存的参数默认值都是经过设计的, 除非有特殊理由, 否则不需要去修改。

节点配置

集群配置

PUT /_cluster/_settings

对所有索引设置

PUT /_all/_settings

动态变更集群配置项

    # cluster settings
    PUT /_cluster/settings
    {
         # 永久变更, 它会覆盖掉静态配置文件里的选项
        "persistent" : {
            "discovery.zen.minimum_master_nodes" : 2 
        },
        # 临时修改 , 重启后清除
        "transient" : {
            "indices.store.throttle.max_bytes_per_sec" : "50mb" 
        }
    }

防止脑裂

discovery.zen.minimum_master_nodes > = ( master 候选节点个数 / 2) + 1 

集群最少需要有两个 node , 才能保证既可以不脑裂, 又可以高可用

Segment

es 为了搜索性能不被后台 merge 影响 , 对它进行了限速。

如果使用的是 SSD , 需要手动调高 elasticsearch 的 throttle 。[尤其是对高写入的服务]

PUT /_cluster/settings
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "100mb"
    }
}

故障恢复

恢复集群

当有节点掉线的时候 , 其余节点选举 master , rebalance data , copy shards , 整个集群网络和IO会大幅度上升 , 等到有节点加入的时候 , 该节点会删除本地已经被复制的数据, 然后再进行 rebalance . 这个过程需要大量时间。但是假如数据的 replica set 存在于当前活跃的节点中 , 则整个集群仍旧是出于可用状态 , status 是 yellow .

但在实践中发现 , 当一台机器被打挂后 , 压力均摊到其余机器, 会把其余机器也给打挂。在成本不允许添加更多机器时, 我们需要做好随时重启集群的准备。这个时候, es 漫长的恢复流程是一个噩梦。

设置下几个个参数可以让我们

  1. 等待集群至少存在 8 个节点 后才能进行数据恢复。
  2. 等待 5 分钟,或者 10 个节点上线后,才进行数据恢复,这取决于哪个条件先达到。
    gateway.recover_after_nodes: 8
    gateway.expected_nodes: 10
    gateway.recover_after_time: 5m
    

这些配置只能设置在 config/elasticsearch.yml 文件中或者是在命令行里(它们不能动态更新)它们只在整个集群重启的时候有实质性作用。

另外, 我们也能够通过设置延迟分配来阻止 当某个 Node 临时 下线时候的延迟分配。下面的操作能够延迟5分钟分配, 若此时 Node 又恢复回来了则不进行再分配。

PUT /_all/_settings 
{
  "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m" 
  }
}

滚动重启/升级

前期准备

  • 可能的话,停止索引新的数据。
  • 禁止分片分配。这一步阻止 Elasticsearch 再平衡缺失的分片,直到你告诉它可以进行了。
    PUT /_cluster/settings
    {
        "transient" : {
            "cluster.routing.allocation.enable" : "none"
        }
    }
    
  • 关闭单个节点
  • 执行维护/升级
  • 重启节点,然后确认它加入到集群了
  • 重启分片分配
    PUT /_cluster/settings
    {
        "transient" : {
            "cluster.routing.allocation.enable" : "all"
        }
    }
    
  • 对其它Node同样进行此类操作

Tips

  1. 降低 Input 组件并发程度(降低实时性要求), fluentd 线程从 4 减少到 1 时 , ES 有负载有明显降低。