ElasticSearch Operation

1.Elasticsearch内存分布

memory

大小可预估的三个区域

  • Query/Filter Cache:查询缓存,可以通过indices.cache.filter.size/indices.cache.query.size配置;
  • Fielddata Cache:聚合缓存,可以通过indices.fielddata.cache.size配置.配合indices.breaker.fielddata.limit使用可以预防OOM;
  • Index Buffer:写入缓冲,可以通过indices.memory.index_buffer_size设置,粒度可以精确到每个shard

三个不可预估的区域

  • Result Window:结果集,1.x支持int.max的结果集,非常容易OOM,2.2开始可以通过index.max_result_window控制,默认10000
  • Bulk Queue:批处理队列,受到单个BulkRequest大小的影响,Queue过大可能会导致内存占用较多
  • Segment:索引文件,与数据量成正比

Result Window,是非常容易被人忽视的内存占用,主要是与查询结果大小有关,一般情况下,这里都不是问题点,只有在特殊情况下会造成OOM(更多信息可以参考分页查询),例如:

  • Top(N)的查询,N=10000000
  • 翻页查询,from=10000000, size=1000

其它注意事项

  • 严格控制Segment
    • 索引数量
    • 数据量,高权重
    • 随着业务的增长,这部分内存会逐步侵占整个 Old memory
  • Filter Cache
    • filter查询才进入缓存
  • Fielddata Cache
    • 统计要合理规划size
    • 资源允许的情况下,申请离线集群
  • Result Window
    • 防止Top陷阱
    • 防止过大的聚合

2.索引相关

2.1 rollover

Elasticsearch 从5.0开始,为日志场景的用户提供了一个很不错的接口,叫rollover.其作用是:当某个别名指向的实际索引过大的时候,自动将别名指向下一个实际索引.

因为这个接口是操作的别名,所以我们依然需要首先自己创建一个开始滚动的起始索引:

curl -XPUT 'http://localhost:9200/indexd-01.01-1' -d '{
    "aliases": {
        "logstash": {}
    }
}'

然后就可以尝试发起 rollover 请求了:

curl -XPOST 'http://localhost:9200/indexd/_rollover' -d '{
    "conditions": {
        "max_age":   "1d",
        "max_docs":  10000000
    }
}'

上面的定义意思就是:当索引超过 1 天,或者索引内的数据量超过一千万条的时候,自动创建并指向下一个索引.

这时候有几种可能性:

  • 条件都没满足,直接返回一个 false,索引和别名都不发生实际变化
     {
         "old_index" : "indexd-01.01-1",
         "new_index" : "indexd-01.01-1",
         "rolled_over" : false,
         "dry_run" : false,
         "acknowledged" : false,
         "shards_acknowledged" : false,
         "conditions" : {
             "[max_docs: 10000000]" : false,
             "[max_age: 1d]" : false
         }
     }
    
  • 还没满一天,满了一千万条,那么下一个索引名会是:indexd-01.01-000002
  • 还没满一千万条,满了一天,那么下一个索引名会是:indexd-01.02-000002

3.节点相关

3.1 节点下线

集群中个别节点出现故障预警等情况,需要下线,也是Elasticsearch运维工作中常见的情况.如果已经稳定运行过一段时间的集群,每个节点上都会保存有数量不少的分片.这种时候通过reroute接口手动转移,就显得太过麻烦了.这个时候,有另一种方式:

curl -XPUT 127.0.0.1:9200/_cluster/settings -d '{
  "transient" :{
      "cluster.routing.allocation.exclude._ip" : "10.0.0.1"
   }
}'

Elasticsearch集群就会自动把这个 IP 上的所有分片,都自动转移到其他节点上.等到转移完成,这个空节点就可以毫无影响的下线了. 和_ip类似的参数还有_host,_name等.此外,这类参数不单是cluster级别,也可以是index级别.

3.2 冷热数据的读写分离

Elasticsearch集群一个比较突出的问题是: 用户做一次大的查询的时候, 非常大量的读 IO 以及聚合计算导致机器 Load 升高, CPU 使用率上升, 会影响阻塞到新数据的写入, 这个过程甚至会持续几分钟.所以,可能需要仿照 MySQL 集群一样,做读写分离.

实施方案

  1. N 台机器做热数据的存储, 上面只放当天的数据.这 N 台热数据节点上面的elasticsearc.yml中配置 node.attr.tag: hot
  2. 之前的数据放在另外的 M 台机器上.这 M 台冷数据节点中配置 node.attr.tag: stale
  3. 模板中控制对新建索引添加 hot 标签:
    {
     "order" : 0,
     "template" : "*",
     "settings" : {
       "index.routing.allocation.include.tag" : "hot"
     }
    }
    
  4. 每天计划任务更新索引的配置, 将tag更改为stale, 索引会自动迁移到 M 台冷数据节点
    curl -XPUT http://127.0.0.1:9200/indexname/_settings -d'
    {
    "index": {
       "routing": {
          "allocation": {
             "include": {
                "tag": "stale"
             }
          }
      }
    }
    }'
    

这样,写操作集中在N台热数据节点上,大范围的读操作集中在M台冷数据节点上.避免了堵塞影响.

该方案运用的,是Elasticsearch中的allocation filter 功能.

4.集群相关

5.集群版本升级

按照ES官方设计,有restart upgraderolling upgrade两种可选的升级方式.对于 1.0 版本以上的用户,推荐采用rolling upgreade方式.

5.1 rolling upgreade

rolling upgrade的步骤大致如下:

  1. 暂停分片分配
  2. 单节点下线升级重启
  3. 开启分片分配
  4. 等待集群状态变绿后继续上述步骤.

但是,对于主要负载是数据写入的 Elastic`Stack 场景来说,却并不是这样!

实际运行中,步骤 2 的 ES 单节点从restart到加入集群,大概要100s左右的时间.也就是说,这100s内,该节点上的所有分片都是unassigned状态.而按照Elasticsearch的设计,数据写入需要至少达到 replica/2+1个分片完成才能算完成.也就意味着你所有索引都必须至少有1个以上副本分片开启.

但事实上,很多日志场景,由于写入性能上的要求要高于数据可靠性的要求,大家普遍减小了副本数量,甚至直接关掉副本复制.这样一来,整个rolling upgrade期间,数据写入就会受到严重影响,完全丧失了 rolling 的必要性.

其次,步骤3中的ES分片均衡过程中,由于ES的副本分片数据都需要从主分片走网络复制重新传输一次,而由于重启,新升级的节点上的分片肯定全是副本分片(除非压根没副本).在数据量较大的情况下,这个步骤耗时可能是几十分钟甚至以小时计.而且并发和限速上稍微不注意,可能导致分片均衡的带宽直接占满网卡,正常写入也还是受到影响.

所以,对于写入压力较大,数据可靠性要求偏低的实时日志场景,依然建议大家进行主动停机式的restart upgrade.

5.2 restart upgrade

restart upgrade的步骤如下:

  1. 首先适当加大集群的数据恢复和分片均衡并发度以及磁盘限速:
curl -XPUT http://127.0.0.1:9200/_cluster/settings -d '{
  "persistent" : {
    "cluster" : {
      "routing" : {
        "allocation" : {
          "disable_allocation" : "false",
          "cluster_concurrent_rebalance" : "5",
          "node_concurrent_recoveries" : "5",
          "enable" : "all"
        }
      }
    },
    "indices" : {
      "recovery" : {
        "concurrent_streams" : "30",
        "max_bytes_per_sec" : "2gb"
      }
    }
  },
  "transient" : {
    "cluster" : {
      "routing" : {
        "allocation" : {
          "enable" : "all"
        }
      }
    }
  }
}'
  1. 暂停分片分配:
curl -XPUT http://127.0.0.1:9200/_cluster/settings -d '{
  "transient" : {
    "cluster.routing.allocation.enable" : "none"
  }
}'
  1. 通过配置管理工具下发新版本软件包.
  2. 公告周知后,停止数据写入进程(即 logstash indexer 等)
  3. 如果使用 Elasticsearch 1.6 版本以上,可以手动运行一次 synced flush,同步副本分片的 commit id,缩小恢复时的网络传输带宽:
curl -XPOST http://127.0.0.1:9200/_flush/synced
  1. 全集群统一停止进程,更新软件包,重新启动.
  2. 等待各节点都加入到集群以后,恢复分片分配:
curl -XPUT http://127.0.0.1:9200/_cluster/settings -d '{
  "transient" : {
    "cluster.routing.allocation.enable" : "all"
  }
}'

由于同时启停,主分片几乎可以同时本地恢复,整个集群从red变成yellow只需要 2 分钟左右.而后的副本分片,如果有synced flush,同样本地恢复,否则网络恢复总耗时,视数据大小而定,会明显大于单节点恢复的耗时.

  1. 如果有synced flush,建议等待集群变成green状态后,恢复写入.否则在集群变成 yellow 状态之后,即可着手开始恢复数据写入进程.

results matching ""

    No results matching ""