记录每一次的分享与讨论,
为了下一次的碰撞而准备。

如何监控Elasticsearch

简述Elasticsearch

Elasticsearch 是一个开源的分布式文档存储和搜索引擎,可以近实时的存储和检索数据。
Elasticsearch 是一个构建在Lucene之上的、采用纯Java实现的分布式搜索引擎。

Elasticsearch 采用Json的格式来描述数据,并通过RESTful API 与集群进行数据的交互。
Elasticsearch 可以很容易的通过新增节点来进行水平扩展,解决机器性能的瓶颈.
目前Elasticsearch 在大部分公司里主要提供了三种解决方案 海量存储数据分析实时检索

为什么要监控ES

监控可以在问题、灾难发生之前捕获异常指标(趋势)。

监控可以用于快速定位问题发生的原因以及发生的位置 。

监控抓取的数据可以用于告警、以及后期的指标分析、资源预测。

可以通过监控了解Elasticsearch当前的负载能力、以及集群存在的瓶颈。

如何去监控ES

相信大家都坐过汽车,看过驾驶室内的各种仪表盘上的参数,通过仪表盘我们能清楚的
知道,汽车是否在发动, 汽车里的油是否可以驾驶100公里,行驶速度是否超过阈值,
变速箱是否有异常等等等。。。

ES 也是一样,我们需要在一个仪表盘里通过一些指标来监控集群,通过这些指标来,
了解集群运行状态、观察集群资源使用情况、集群存在的瓶颈等等需要关注的点。

构建ES(集群)监控仪表盘

监控ES是否健康

Elasticsearch 集群有三种健康状态,1) GREEN、2) YELLOW、3) RED

  • GREEN
    所有主分片和副本分片都处于 活动 状态
  • YELLOW
    所有主分片都处于活动状态,部分副本分片处于 未存活 状态。
  • RED
    部分主分片处于 未存活 状态

仅仅通过集群状态这个单一指标,是不可能准确的判断集群当前的状态。
因为ES在创建新索引时,集群健康状态会从 red -> yellow -> green ,
理论上这个初始化的过程1秒内就可完成,如果不结合以下的指标共同判断,
有可能造成误判。

【集群健康指标 】

ES Cluster Health API -> /_cluster/health?pretty

  • 集群健康状态
    cluster.health.status
  • 集群存活节点数
    cluster.health.number_of_nodes
  • 集群存活数据节点数
    cluster.health.number_of_data_nodes
  • 集群主分片活动数
    cluster.health.active_primary_shards
  • 集群分片活动数
    cluster.health.active_shards
  • 集群正在迁移分片数
    cluster.health.relocating_shards
  • 集群正在初始化分片数
    cluster.health.initializing_shards
  • 集群未分配分片数
    cluster.health.unassigned_shards
  • 集群延迟分配分片数
    cluster.health.delayed_unassigned_shards
  • 集群待处理任务数
    cluster.health.number_of_pending_tasks

监控ES的查询、写入的吞吐量和延迟

在Elasticsearch 中,查询过程主要分为两个阶段,1) 查询阶段 2) 获取阶段

在监控查询指标之前,首先来了解ES的检索过程,只有了解检索的步骤才能更细粒度的监控
集群的查询状态,以及为了理解查询指标的趋势所代表的意义,奠定了基础。
( 部分图片摘自于网络,文章底部会贴出原始地址。)

  1. 客户端发送一个查询请求至 NODE 2
  2. NODE 2 (协调节点,第一个查询请求发送到哪个节点,哪个节点就做为协调节点)把相同的查询请求发送到
    索引的每一个分片(相同的分片只请求一次,该分片可以是主分片、也可以是副本分片 )上。
  3. 每个分片都在本地节点执行查询,并把查询的结果发送到NODE 2(协调节点)上,由协调节点把每个分片
    排序后的结果放入一个全局的优先队列中。
  4. 协调节点发送批量的获取请求到相关的分片上
  5. 每个分片加载命中的文档,并把结果分发到协调节点上。
  6. 最终由协调节点把查询结果交付给客户端

【查询指标】

ES Total Search API

Cluster Level -> /_stats?pretty&filter_path=_all.total.search

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.indices.search

Index Level -> /_stats?pretty&filter_path=indices.*.total.search

  • 查询总数
    indices.search.query_total
  • 查询总耗时
    indices.search.query_time_in_millis
  • 当前正在进行的查询数
    indices.search.query_current
  • 获取的总数
    indices.search.fetch_total
  • 获取总耗时
    indices.search.fetch_time_in_millis
  • 当前正在进行的获取数
    indices.search.fetch_current

【根据原始指标,计算查询性能指标】

  • 查询负载(Query Load)
    监控任意时刻,集群正在处理的查询请求数量(粗略估算,可以结合查询线程池判断集群瓶颈)。
  • 查询延时(Query Latency)
    通过查询耗时、查询数计算出每个查询的平均耗时,判断是否存在资源瓶颈或者需要优化的查询语句。
  • 获取负载(Fetch Load)
    监控任意时刻,集群正在处理的获取请求数量
  • 获取延时(Fetch Latency)
    通过获取耗时、获取数计算出每个获取请求的平均耗时,若该指标在稳定的增长,
    考虑是否是磁盘变慢了、请求文档数过多等

了解集群写入数据的过程。

当一个新的数据写入到索引中,或者对于已经存在于索引中的数据进行更新、删除等操作,
每个分片都会通过这两个阶段 1) refresh 2) flush

被索引的新文档,在ES中是不能立即直接查询的。 首先ES会把新的文档写入到
内存缓冲区 中,并等待下一个indnex refresh, 若没有显示指定,索引默认是每秒刷新一次。
刷新后,意味着新索引的文档可以被搜索到了。

  1. 索引刷新(refresh)过程
  2. 索引持久化(实在不想把flush 翻译成 刷新,因为flush是持久化操作,所以这里用持久化代替)过程
    被索引的新文档会同时的被写入到内存缓冲区和translog(事务操作日志,防止数据丢失)中。
    当执行flush 操作时,所有内存缓冲区内的新文档将会被刷新(refresh, 生成一个新段,并可搜索),
    新生成segment 会被持久化到磁盘上,translog中的数据会被清空。

【写入指标】

ES Total Indexing API

Cluster Level -> /_stats?pretty&filter_path=_all.total.indexing

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.indices.indexing

Index Level -> /_stats?pretty&filter_path=indices.*.total.indexing

  • 索引文档总数
    indices.indexing.index_total
  • 索引文档总耗时
    indices.indexing.index_time_in_millis
  • 当前正在进行的索引文档数
    indices.indexing.index_current
  • 索引刷新总数
    indices.refresh.total
  • 索引刷新总耗时
    indices.refresh.total_time_in_millis
  • 索引持久化总数
    indices.flush.total
  • 索引持久化总耗时
    indices.flush.total_time_in_millis

【根据原始指标,计算写入性能指标】

  • 索引负载 (Indexing Load)
    监控任意时刻,集群正在处理的索引请求数量(粗略估算,可以结合索引线程池判断集群瓶颈)
  • 索引延时 (Indexing Latency)
    通过索引耗时、索引次数计算出每个索引操作的平均耗时,判断是否存在资源瓶颈或者
    需要优化的索引数据结构。
  • 持久化延时 (Flush Latency)
    通过持久化耗时、持久化次数计算出每个持久化操作的平均耗时,根据性能要求优化持久化频率。
  • 刷新延时 (Refresh Latency)
    通过刷新耗时、刷新次数计算出每个刷新操作的平均耗时,根据实时性与吞吐量,进行调整刷新频率。

监控ES内存与GC使用情况?

监控节点内存的使用情况,为了既不让ES处于崩溃的边缘又不让ES浪费过多的内存资源。

在这里我简述下关于内存分配过大、分配过小会给ES集群带来的风险

  • 内存过小
    • 容易出现 OOM(out of memory) 错误,造成节点异常脱离集群。
    • 造成大量GC停顿,导致吞吐量下降。
    • 无法执行大数据量的复杂查询、聚合、排序。

  • 内存过大
    • FGC(FULL GC)长时间停顿,会导致节点无法响应心跳检查而节点脱离集群。
    • 年轻代回收时间过长,降低写入、查询吞吐量。

【内存指标、GC指标】

ES Node JVM Memory API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.jvm.mem

ES Node JVM GC API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.jvm.gc

  • 堆内存使用百分比
    nodes.jvm.mem.heap_used_percent
  • 堆内存分配值
    nodes.jvm.mem.heap_committed_in_bytes
  • 堆内存已使用值
    nodes.jvm.mem.heap_used_in_bytes
  • 非堆内存分配值
    nodes.jvm.mem.non_heap_committed_in_bytes
  • 非堆内存已使用值
    nodes.jvm.mem.non_heap_used_in_bytes
  • 年轻代GC总数
    nodes.jvm.gc.collectors.young.collection_count
  • 年轻代GC总耗时
    nodes.jvm.gc.collectors.young.collection_time_in_millis
  • 年老代GC总数
    nodes.jvm.gc.collectors.old.collection_count
  • 年老代GC总耗时
    nodes.jvm.gc.collectors.old.collection_time_in_millis

内存分配的大小会直接的影响集群的GC情况,而GC的表现会直接影响
整个ES集群的吞吐量,请求延时等集群性能。
GC 的调整除了内存的分配外,还需要通过监控来进行调整,
最终使GC能够完成稳定、高吞吐量的优化目标。

监控ES节点宿主机使用情况?

由于节点所在的宿主机的性能决定了,ES节点的性能,
所以除了要关注ES的指标,同样要关注机器的资源及性能指标。
在这篇文章里,主要使用的是由ES提供的的API,你也可以通
过zabbix 、beats等组件抓取更详细的宿主机指标。

【宿主机资源、性能指标】

ES Node DISK API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.fs.total&human

ES Node CPU USAGE API

Node Level ->/_nodes/stats?pretty&filter_path=**.host,**.process.cpu

ES Node File Ddecriptors API

Node Level -> /_nodes/stats?pretty&filter_path=**.host
,**.process.open_file_descriptors

ES Node HTTP CONNECTION API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.http

ES Node Transport CONNECTION API

Node Level -> /_nodes/stats?pretty&filter_path=**.host
,**.transport.server_open

ES Node Transport Network Traffic API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.transport.rx_count
,**.transport.rx_size_in_bytes,**.transport.tx_count,**.transport.tx_size_in_bytes

  • 节点挂载磁盘大小
    nodes.fs.total.total_in_bytes
  • 已使用节点挂载磁盘大小
  • 进程CPU使用百分比
    nodes.process.cpu.percent
  • 进程文件句柄打开总数
    nodes.process.open_file_descriptors
  • 任意时刻,通过 Rest API 访问集群的总数
    nodes.http.current_open
  • 任意时刻,通过 Transport 客户端 访问集群的总数
    nodes.transport.server_open
  • 任意时刻,transport 客户端流量指标
    nodes.transport.rx_count
    nodes.transport.rx_size_in_bytes
    nodes.transport.tx_count
    nodes.transport.tx_size_in_bytes

监控ES节点线程池使用情况

Elasticsearch 维护了多种线程池,通过线程池和宿主机的资源
使用情况,可以容易的判断集群是否有压力,哪个节点有压力。
把问题定位清楚了,解决问题就轻而易举了。

当节点处理能力不够时,节点会把新的请求放入到队列中
(有界队列、无界队列),等待节点有资源空闲时,
再来处理队列中的请求,假定线程池维护了一个大小为
100的有界队列,当请求并发过大时,会把队列给填满,
当队列填满后,再来一个新的请求时,集群会立即对该请求
返回一个拒决响应,这个降级策略是为了保证集群的稳定性。

通过监控可以评估节点资源使用情况 、尽量不把ES放在
随时崩溃的风险中。

【线程池指标】

ES Node Thread Pool API

Node Level -> /_nodes/stats?pretty&filter_path=**.host,**.thread_pool

  • BULK 线程池(批量写操作)
    nodes.thread_pool.bulk.threads
    nodes.thread_pool.bulk.queue
    nodes.thread_pool.bulk.active
    nodes.thread_pool.bulk.rejected
  • GENERIC 线程池 (集群基本操作,e.g. 节点发现工作)
    nodes.thread_pool.generic.threads
    nodes.thread_pool.generic.queue
    nodes.thread_pool.generic.active
    nodes.thread_pool.generic.rejected
  • SEARCH 线程池 (集群查询操作,e.g. API count/search/suggest等查询)
    nodes.thread_pool.search.threads
    nodes.thread_pool.search.queue
    nodes.thread_pool.search.active
    nodes.thread_pool.search.rejected
  • INDEX 线程池 (集群单文档写操作,e.g. API index/deletet等查询)
    nodes.thread_pool.index.threads
    nodes.thread_pool.index.queue
    nodes.thread_pool.index.active
    nodes.thread_pool.index.rejected

线程池的种类很多,这里主要提取出最重要的几类。
线程池第一个要关注的就是active ,看看active 是否能跑满
threads,如果长时间跑不满,就要考虑下资源浪费的问题,
第二个要关注的是queue,若是queue有明显的上升趋势,
要考虑是否是集群资源无法满足当前的业务需求了,
评估是否要加资源。第三个,也是最重要的一个,
就是rejected ,如果集群出现rejected ,首先要观察集群
的健康状态,是否有节点丢失导致处理能力不够,而出现
服务降级,如果节点没有异常,出现rejected 可定位成
集群处理能力不够。

文中部分图片出处

未经允许不得转载:Elasticsearch Club » 如何监控Elasticsearch

分享到:更多 ()
希望每个得到帮助的朋友,能够赞助一波:

    

评论 2

评论前必须登录!

 

  1. #1

    写的不错,五毛拿好~

    Ricky 回复:

    我会继续努力的 ^ _ ^

    aloneali1年前 (2017-12-20)