ELasticSearch优化设置

本文总阅读量

前记

最近一直在接触ElasticSearch,非常好用,不过需要记的东西太多了,就把优化项记录下来

1.ElasticSearch相关配置

  • path.data: /var/lib/elasticsearch
    别用来存放索引数据
    path.data支持配置多个目录,每个目录都会用来存放数据,但是单个分片会存放在同一个目录内

    1
    2
    3
    4
    5
    path:
    data:
    - /dir/elasticsearch_1
    - /dir/elasticsearch_2
    - /dir/elasticsearch_3
  • path.logs: /var/log/elasticsearch
    用来存放运行日志

  • cluster.name: elasticsearch
    集群名称,可以用来区分不同集群。每个节点需要配置相同的集群名才能加入同一个集群中,且每个节点只能加入一个集群。

  • node.name: so1n-node
    节点名称,默认情况下节点名称是操作系统的主机名.

  • network.host: 127.0.0.1
    默认配置下,Elasticsearch绑定的是一个环回地址127.0.0.1 ,这只适合在单机开发时使用。在正式环境中,为了保证该节点能够被其它节点找到,形成一个集群,需要设置一个非环回地址.在内网中一般填写自己的内网ip

  • discovery.seed_hosts: [127.0.0.1, 10.0.0.1]
    服务发现种子主机,用于本机可以去连接其他已经存在的机器,融入已有集群,
    如果是在同一个机器上面部署多个实例,可以不用填写,Elasticsearch默认会从本机的9300-9305端口尝试去连接其它节点.
    对于每个机器每个实例,一起创建集群时,每个机器都配置其他机器的ip,如果是向某集群添加新的机器,新的机器添加好集群已有机器ip即可.
    discovery.seed_hosts可以是ip、ip:端口和域名。如果配置是ip,Elasticsearch默认会使用transport.profiles.default.port配置项的端口,该端口默认为9300;如果配置是域名,且该域名下绑定了多个ip,ES会尝试去连接多个ip。

  • cluster.initial_master_nodes: [“so1n-node”]
    初始主节点列表,当开启一个全新的集群时,会有一个集群的引导步骤,这步骤用来确定哪些节点参与第一次的主节点选举,这些步骤会从初始主节点列表里面的节点协商出一个主节点.

    2.ElasticSearch相关优化配置

  • 内存锁bootstrap.memory_lock: true
    内存锁可以在ES启动时,锁住一段堆内存,保证堆内存的数据不会被挤到磁盘中(对应Linux中的mlockall 系统调用).

  • 更改Refresh间隔index.refresh_interval: 1s
    ELasticsearch是一个近实时的库,该参数会指引ELasticsearch间隔多少时间把数据写入,每次写入都需要使用大量io,如果对数据的及时性要求不高,可以通过增加时间间隔,提升机器性能,但是也意味着占用了更多heap,所以要确保机器的heap足够大.

  • 提前加载数据到缓存 index.store.preload: [“nvd”,”dvd”]
    机器重启时,缓存会被清空,设置index.store.preload后,可以告知系统可以把指定文件扩展名文件提早加载到缓存.
    或者可以在创建索引的时候执行

    1
    2
    3
    4
    5
    6
    PUT index
    {
    "settings":{
    "index.store.preload":["nvd","dvd"]
    }
    }
  • 配置段合并indices.store.throttle.max_bytes_per_sec: 20mb
    Lucene以段的形式存数据,当有新的数据写入到索引时,Lucene就会自动创建一个新的段,随着数据的增加,段的数量会越来越多,消耗的文件句柄数以及cpu也变大,导致查询效率下降.
    而由于lucene段的合并会消耗i/o以及计算,所以默认的ES策略比较保守:

    • 当索引的写入效率下降时,也就是段的合并速度低于索引的写入速度,ES会把索引的写入线程数量减少到1.这样可以避免出现段数量的堆积,同时会打印now throttling indexing.
    • ES对段的合并默认速度为20m/s,这一值是针对机械硬盘设置的.
      我们可以通过更该默认的段合并速度来提升段的合并速率,如:
      1
      2
      3
      4
      5
      6
      PUT /_cluster/settings 
      {
      "persistent" : {
      "indices.store.throttle.max_bytes_per_sec" : "100mb"
      }
      }
  • index_buffer_size 的设置
    可以通过设置成百分数或者具体的大小(最多512mb),当大于这个值时会触发refresh

    1
    2
    3
    indices.memory.index_buffer_size:10%(默认)
    indices.memory.min_index_buffer_size: 48mb(默认)
    indices.memory.max_index_buffer_size: 512mb(默认)
  • 修改 translog 相关的设置
    Flush 的主要目的是把缓存中的段持久化到硬盘,当 Translog 的数据量达到 512MB 或者 FLush间隔超过30 分钟时,会触发一次 Flush,可以通过更改

    • index.translog.flush_threshold_size: 512mb
    • index.translog.sync_interval:5s
    • index.translog.durability:async # 写入方式,async是异步写入
      的值来决定Translog的数据量达到多少时才进行Flush的操作.不过值越大,也就意味着会占用更过的内存
  • Cache
    ES 提供了几种缓存,可以根据业务需求决定是否开启缓存和缓存大小

    • QueryCache:使用fliter查询时的缓存,如果fliter查询比较多,则可以设置QueryCache缓存
      1
      2
      indices.queries.cache.size: 10%(默认),//可设置成百分比,也可设置成具体值,如256mb。
      index.queries.cache.enabled:true(默认开启QueryCache)
    • FieldDataCache: 缓存聚合类运算或着排序的结果
      1
      indices.fielddata.cache.size:30%
    • ShardRequestCache:缓存每个协调节点的聚合结果(只缓存 hits.total, aggregations, suggestions 类型的数据,并不会缓存hits的内容)
      1
      2
      index.requests.cache.enable: true
      indices.requests.cache.size: 1%(默认)
  • 推迟分片的分配
    当节点瞬时中断是,默认情况下,集群会等待一分钟来查看节点是否会重新加入,如果在期间节点重新加入,这时节点会保持现有的分片数据,不会触发新的分片分配,可以减少es自动再平衡可用分片时带来的开销,可以通过如下设置,_all代表所有索引

    1
    2
    3
    4
    5
    6
    PUT /_all/_settings 
    {
    "settings": {
    "index.unassigned.node_left.delayed_timeout": "5m"
    }
    }
  • 控制mapping

    • 尽量避免使用nested或 parent/child,或者控制nested fields字段的数量, 每一个nested field, 都会生成一个独立的document, 这将使Doc数量剧增,影响查询效率,es默认50
    • 控制索引的字段数量
    • 控制mapping深度
      1
      2
      3
      index.mapping.nested_fields.limit :50 # nested field数量限制
      index.mapping.total_fields.limit:1000 # 控制索引字段数量
      index.mapping.depth.limit: 20 #控制mapping深度

      3.ElasticSearch Client优化

      常用写入ElasticSearch有logstash以及自己利用ELasticSearch Restful API 编写的API,其中logstash基本是开箱即用,基本修改pipeline即可,详见Logstash Pipeline,ELasticSearch Restful API 相关优化见下面:
  • 字段类型可以使用keyword就使用keyword

  • 对于不需要聚合和排序的索引字段禁用doc values
    Doc Values 默认对所有字段启用,除了 analyzed strings,但我们有写字段可以不需要排序和聚合,而关闭了doc values后可以节省磁盘空间,同时会提升索引的速度.
    设置mapping时,在想要禁用doc values的字段设置doc_values: false即可

  • 使用Bulk Api提交数据
    每次提交的数据量为多少时,能达到最优的性能,主要受到文件大小、网络情况、数据类型、集群状态等因素影响。
    通用的策略如下:Bulk 默认设置批量提交的数据量不能超过 100M。数据条数一般是根据文档的大小和 服务器 性能而定的,但是单次批处理的数据大小应从 5MB~15MB 逐渐增加,当性能没有提升时,把这个数据量作为最大值。

  • 使用scroll查询
    在查询数据时,我们可以使用from+size来模拟分页,但是form查询时,每次都需要查询,聚合数据,再进行排序,最后返回[from, from + size]的size条数据.不能利用好上次查询的缓存.
    为此ES提供了类似Redis的Scan的Scroll和Scroll-Scan两种查询模式:

    • Scroll:第一次查询时,会先在分片上根据查询条件查询数据(Es默认限制search api搜索的数据最高为10000条, scroll也不例外,需要更改配置),然后协同节点聚合数据,合并,排序,并把数据缓存到内存,然后再返回部分数据和scorll_id,下次请求可以带上scorll_id参数获取下一段数据
    • Scroll-Scan: 与Scroll相似,但不会去计算文本相似度和排序,也不支持聚合操作,所以性能会更加高效.

**注: 由于Scroll和Scroll-Scan是根据第一次查询结果的数据缓存到内存,后面的数据增删改查都不能影响到查询的结果,所以后续的Scroll和Scroll-Scan请求操作都不是实时. **

  • 按时间间隔创建index
    按照自己数据量的多少,设置一个月或者一天等一个索引
    由于索引在创建后就无法更改分片和副本数量,除非进行重建索引操作,但重建索引操作会随着数据量的提升而变得耗时,同时处理好每个索引的时间间隔会更容易做优化,如对索引的merge.所以我们需要按照自己的数据量大小去设置索引,如果每天的数据量很大,则可以按天创建索引,如果是一个月积累起来导致数据量很大,则可以一个月创建一个索引。
  • 如果没有需求,不要自定义id
    如果客户端有自定义id,Elasticsearch会在数据传入时,检查该id文档是否已经存在于相同的分片中.这一操作会随着索引的量变多而更加消耗机器的性能
  • 如果不需要查询数据本身,search请求中,query要设置size=0
    例如我们只需要使用query的aggs查询时,我们就可以设置size=0,这样子ElasticSearch就不会把所有文档数据查出来,而只是按照aggs特性查询count
  • 查询数据时,尽量使用具体时间
    如果自己加了一层缓存层,那就可以不看此说明.
    在查询时间范围时,我们一般会给日期字段设置now这类的参数,但这类查询一般是不会被缓存的.只有填写明确的时间参数,ELasticSearch才会对数据进行缓存.
  • 调用search api时可以通过preference参数设置ELasticSearch的偏好查询
    默认情况下,假设我们一个索引有a个shard和b个副本,当一个查询请求过来的时,a个shard的数据都会被查询,然后每个shard随机查询主shard或者replia.
    • preference=_local
      优先在本地节点上的分片查询数据,如果查询失败则去其他节点上的分片查询,本地节点没有IO问题但有可能造成负载不均问题;数据量是完整的。
    • preference=_only_local
      仅在分配给本地节点的分片沙勋
    • preference=_primary
      只在主分片查询,不查询副本数据,一般数据完整
    • preference=_primary_first
      优先在主分片查询,如果主分片挂了则去副本查询,一般数据完整.
    • preference=_prefer_node
      优先在指定的节点查询,一般数据完整.
    • preference=_shards
      在指定分片中查询,数据可能不完整.该选项可以与其他的选项一起使用,如:_shards:2,3|_local
    • preference=_only_node
      在指定id的节点中的分片查询,数据可能不完整
    • preference=_only_nodes
      在自定的多个节点查询,可以使用通配符
  • 调整search api 的batched_reduce_size
    默认情况下,聚合操作是在协调节点需要等待所有的分片都取回结果后才执行,使用batched_reduce_size参数可以不等待全部分片返回结果,而是在指定数量的分片返回结果只会就可以先处理一部分(reduce)。这样可以避免协调节点在等待全部结果的过程中占用大量内存,避免极端情况下可能导致的OOM。该字段默认值512.
  • 查询时设置查询条件的Routing(需要配置好mapping)

注:需要配置好mapping,同时要注意由于配置routing导致分片不均的情况,需要把数据量小的routing合并成一个大的routing,或者多个维度组合成一个tag
ES中有种类似于tag的东西,叫做路由,在创建文档的时候,可以给文档添加一个路由属性的tag,有了tag后,ES会有两个优化:
- 拥有相同路由属性的文档,无论主分片还是副本,都会被分配到相同的一个分片上
- 查询时,设置routing参数后,ES会直接定位到目标分片,避免查询到所有分片和经过协调节点的二次排序.当没有设置routing参数,先依照协调节点的分配,查询所有分片,然后协调节点根据每个分片的搜索结果进行排序,再返回数据

4.ELasticSearch所在机器相关优化配置

  • 设置堆内存(配置文件/etc/elasticsearhc/jvm.options)
    修改下面的两个参数再重启elasticsearch即可

    1
    2
    -Xms2g 
    -Xmx2g

    默认情况下,Elasticsearch中JVM堆内存的最小值和最大值为1GB,在生产模式下,堆内存容量是非常重要的,需要确保Elasticsearch有足够的堆内存可用。我们可以在jvm.options 配置文件中,通过配置Xmx 和Xms项来决定JVM堆内存容量
    配置的容量本身也取决于服务器的物理内存,Xmx 和Xms的值不超过物理内存的50%,因为除了给elasticsearch使用内存外,底层的Lucene也需要使用内存,最好是两个各占机器的一半内存(也要考虑机器上的其他服务),同时,最大可设置接近32GB,26GB是安全值

  • 设置文件描述符大小
    Linux默认配置下单个进程最大打开文件描述符数为1024,而elasticsearch在创建索引过程中会打开很多文件,导致一下子就超过linux默认的限制量
    在/etc/security/limits.conf新增下面配置即可

    1
    elasticsearch - nofile 65535

    表示由用户elasticsearch打开的进程,最大的文件描述符为65535(由于linux是使用c 的非负数类型来表示可用文件描述符数,所以最大为65535)

  • 禁止交换空间
    有些Linux系统默认启动交换空间,对于一些程序(例如我的电脑在关闭时,可以把当前数据写入交换空间,下次启动后从交换空间读取数据到内存,这样子就可以避免每次打开都要启动一堆软件了),交换空间是非常有用的,但是对于elasticsearch来说,使用了交换空间后,读写速度会变得很慢,所以我们要对elasticsearch所在的服务器禁用交换空间

    • 临时禁用交换空间
      在Linux上,可以执行命令:sudo swapoff -a 临时关闭操作系统交换空间
    • 永久禁用交换空间(/etc/fstab)
      TODO
    • 配置swappiness
      修改 /etc/sysctl.conf文件,设置vm.swappiness = 1,可以使Linux在一般情况下不使用交换空间,设置0可能引发OOM
    • 使用内存锁
      见1.ElasticSearch相关优化配置的内存锁部分
  • 设置线程
    Elasticsearch中不同的操作有不同的线程池,为了确保Elasticsearch线程正常创建线程,需要设置操作系统的线程数限制。最小值为4096,可通过修改/etc/security/limits.conf来完成设置。

查看评论