Elasticsearch性能监控(二)
上一期我们分享了《 Elasticsearch性能监控(一)》,介绍了两个领域的ES监测指标:查询和索引(indexing)性能和内存分配和垃圾回收;本期我们将继续讲解另外三类监测指标:主机级别的系统和网络指标、指标集群健康状态和节点可用性、资源饱和度和相关错误。
本文是Emily Chang的分享《How to monitor Elasticsearch performance》中文译文的第一部分。这篇文章的原文可以在GitHub(阅读原文)上可以找到。
PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!
前期回顾
Elasticsearch本身提供了大量的指标,可以帮助我们进行故障预检,并在遇到诸如节点不可用、JVM OutOfMemoryError和垃圾回收时间过长等问题时采取必要措施。 通常需要监测的几个关键领域是:
1. 查询和索引(indexing)性能
2. 内存分配和垃圾回收
3. 主机级别的系统和网络指标
4. 集群健康状态和节点可用性
5. 资源饱和度和相关错误
上期我们分享了前两个领域的检测指标,本期我们将继续分享后三个领域的监测指标。
上期分享可查看文章《 Elasticsearch性能监控(一)》
主机级别的系统和网络指标
尽管Elasticsearch提供了很多程序定制的参数指标,但您也应该从各个节点收集和监控主机级别的指标。
磁盘空间
如果您的Elasticsearch集群是写负载型的,那么这个指标将变得更加重要。因为一旦空间不足,您将不能进行任何插入和更新操作,节点也会下线,这应该是您不想看到的。如果节点的可用空间小于20%,您应该利用类似Curator这样的工具,删除一些占用空间较大的索引来释放部分空间。
如果业务逻辑上不允许删除索引,那么另一种方案就是扩容更多的节点,让Master在新节点间重新分配分片(尽管这样会增加Master节点的负载)。
另外需要记住一点,包含需要分析(analyzed)的字段的文档占用的磁盘空间比那些不需要分析(non-analyzed)的字段(精确值)的文档要多得多。
I / O利用率
当segment被创建、查询和合并时,Elasticsearch会进行大量的磁盘读写操作。 对于具有不断经历大量I/O活动的节点的写负载集群,Elasticsearch建议使用SSD来提高性能。
CPU利用率
利用图示来展示不同节点类型的CPU使用情况会很有帮助。例如,可以创建三个不同的图来表示群集中的不同节点类型(例如Data节点,Master节点和Client节点)的CPU使用情况,通过对比图示来发现是否某一种类型的节点过载了。如果您看到CPU使用率增加,这通常是由于大量的搜索或索引工作造成的负载。设置一个通知,以确定您的节点的CPU使用率是否持续增长,并根据需要添加更多的节点来重新分配负载。
网络吞吐量
节点之间的通信是衡量群集是否平衡的关键组成部分。 您需要监视网络以确保网络正常运行,并且能够跟上群集的需求(例如,在节点间复制或分片的重新分配)。 Elasticsearch提供有关集群节点间通信的传输指标,但是您也可以通过发送和接收的字节速率,来查看您的网络正在接收多少流量。
打开的文件描述符
文件描述符用于节点间的通信、客户端连接和文件操作。
如果打开的文件描述符达到你的系统的限制,那么新的连接和文件操作将不可用,直到有旧的被关闭。 如果超过80%的可用文件描述符正在使用中,则可能需要增加系统的最大文件描述符计数。 大多数Linux系统限制每个进程中只允许有1024个文件描述符。 在生产中使用Elasticsearch时,应该将操作系统文件描述符数量设置为更大的值,例如64,000。
HTTP连接
除了Java Client以外的任何语言发送的请求都将使用基于HTTP的RESTful API与Elasticsearch进行通信。 如果打开的HTTP连接总数不断增加,则可能表明您的HTTP客户端没有正确建立持久化连接。 重新建立连接会在请求响应时间内增加额外的时间开销。 因此务必确保您的客户端配置正确,以避免对性能造成影响,或者使用已正确配置HTTP连接的官方Elasticsearch客户端之一。
集群健康状态和节点可用性
集群健康状态
如果集群状态为YELLOW,说明至少有一个副本分片未分配或者丢失。尽管这个时候搜索结果仍然是完整的,但是如果更多的分片消失的话,有可能造成整个索引的数据丢失。
如果集群状态为RED,则表示至少有一个主分片丢失,索引缺少数据,这意味着搜索将返回部分结果,而且新的文档数据也无法索引到该分片。您可以考虑设置一个告警,如果状态为黄色超过5分钟,或者上次检测状态为红色,则触发警报。
初始化(initializing)和未分配(unassigned)状态的分片
当索引首次创建或者节点重新启动时,由于Master节点试图将分片分配给Data节点,所以在转换为“started”或“unassigned”状态之前,该分片将暂时处于“initializing”状态。 如果您看到分片处于初始化状态或未分配状态的时间过长,则可能是群集不稳定的信号。
资源饱和度和相关错误
Elasticsearch节点使用线程池来管理线程对内存和CPU使用。
由于线程池是根据处理器的核数自动配置的,因此调整它们通常是没有意义的。 但是通过请求队列和请求被拒绝的情况,来确定你的节点是否够用是一个不错的主意。如果出现了状况,您可能需要添加更多的节点来处理所有的并发请求。
fielddata和filter cache的使用是另一个需要监控的领域,因为cache的置换可能预示了效率低下的查询或内存压力的迹象。
线程池的请求队列(queues)和拒绝情况(rejections)
每个Elasticsearch节点都维护着很多类型的线程池。具体应该监控哪些线程池,需要根据Elasticsearch的使用场景而定。一般来讲,最重要的几个线程池是搜索(search),索引(index),合并(merger)和批处理(bulk)。
每个线程池队列的大小代表着当前节点有多少请求正在等待服务。 队列的作用是允许节点追踪并最终处理这些请求,而不是直接丢弃它们。但是线程池队列不是无限扩展的(队列越大占用的内存越多),一旦线程池达到最大队列大小(不同类型的线程池的默认值不一样),后面的请求都会被线程池拒绝。
如下图是需要关注的线程池指标
线程池队列
线程池队列并不是越大越好,因为线程池越大占用的资源越多,并且增大了节点宕机时请求丢失的风险。 如果您看到排队和拒绝的线程数量持续增加,则需要尝试减慢请求速率、增加节点上的处理器数量或增加集群中的节点数量。
如下图所示,查询访问尖峰与搜索线程池队列大小中的尖峰是吻合的。
批处理(bulk)的请求队列和请求拒绝
批处理是同时发送多个请求的更有效方式。 通常如果要执行许多操作(创建索引,或者添加,更新或删除文档),则应尝试将请求作为批处理发送,而不是多个单独的请求。批处理请求被拒绝通常与试图在一个批处理请求中索引太多文档有关。虽然据Elasticsearch的文档所说,出现批处理请求被拒绝的情况,不一定是必须要担心的事情,但是您应该尝试实施一些退避策略,以有效处理这种情况。
缓存使用相关指标
在Elasticsearch中,每个查询请求都被发送到索引中的每个分片,然后分别扫描这些分片中的每个段(segment)。 Elasticsearch以每个段为基础缓存查询,以加快响应时间。
在Elasticsearch中,文档中的每个字段可以以两种形式存储:精确值或全文。 精确值(如时间戳或年份)的存储与其索引的方式完全相同,因为您不希望收到查询1/1/16为“2016年1月1日”。如果字段以全文形式存储 ,这意味着它将被分析 - 基本上,它被分解成分词,根据分析器的类型,标点符号和停用词如“是”或“the”可能被删除。 分析器将字段转换为规范化的格式,使其能够匹配更广泛的查询。
看这样一个例子,假设您有一个类型(type)名为location的索引, location的每个文档都包含一个字段city,它被存储为经过分析(analyzed)的字符串。 你索引两个文档:一个在city字段包含“St. Louis”,另一个包含“St. Paul”。 每个字符串将被转成小写,并去掉标点符号,变成词项。 这些词项(terms)被存储在一个倒排索引里,看起来像这样:
分析(analysis)的好处就是当你检索“st.”的时候,所有包含这个词项的文档都会被检索出来。如果您将city这个字段存储为精确值,只有检索“St. Louis”或者“St. Paul”这样的精确值,才能匹配到结果。
Elasticsearch使用两种主要类型的缓存来更快地提供搜索请求: Fielddata和 Filter。
Fielddata cache
Fielddata cache主要用于字段(field)的排序和聚合,这是一个“转置”(uninvert)倒排索引并按照文档的索引顺序为每一个字段创建一个包含所有值的数组的过程。例如,如果我们想从上面的例子中找到任何包含“st”的文档中的唯一的词项列表,我们将
-
扫描倒排索引以查看哪些文档包含该词项(在本例中为Doc1和Doc2);
-
对于步骤1中找到的每个文档,遍历索引中的每个词项来收集分词,从而创建如下图的结构;
-
这个时候倒排索引就已经被“转置”了,并且从每个文档中提取出了唯一的分词(st,louis和paul)。 像这样编译字段数据会消耗大量的堆栈内存,特别是有大量的文档和词项需要处理的时候,因为所有的字段值都会被加载到内存中。
对于1.3版本之前的Elasticsearch,fielddata cache大小是没有限制的。 从1.3版本开始,Elasticsearch添加了一个fielddata断路器,如果查询试图加载需要占用60%以上堆栈内存的fielddata,则会触发该断路器。
Filter cache
Filter cache也使用JVM堆栈,在2.0版本之前,Elasticsearch自动缓存不超过堆栈内存10%容量的filtered queries,并驱逐最近最少使用的数据。从2.0版本开始,Elasticsearch根据segment大小(比如只缓存小于10000条文档的segment)和检索频率(比如只缓存文档数小于索引总文档数3%的segment)来自动优化Filter cache的使用。综上,filter cache相关的指标只有在Elasticsearch 2.0版本之前可以使用。
举个例子,有一个过滤查询(filter query)要返回字段year的值落在2000-2005范围内的文档。在第一次执行过滤查询的过程中,Elasticsearch将创建一个文档过滤规则是否匹配的数据结构(Bitset)(如果文档匹配则为1,否则为0)。之后使用相同过滤规则的查询将复用这些信息来辅助执行。无论何时添加或更新新文档,这个Bitset也都会被更新。如果您使用2.0之前的Elasticsearch版本,则应该注意Filter缓存以及驱逐指标。
下图是需要关注的缓存相关指标
Fielddata cache驱逐
理想情况下,您可能想限制Fielddata被驱逐的数量,因为它们是I/O密集型的。如果您看到大量的驱逐,并且目前无法增加内存,Elasticsearch建议将fielddata缓存限制为堆栈内存的20%(可以在elasticsearch.yml文件中配置)。当fielddata达到堆栈内存的20%时,它将驱逐最近最少使用的fielddata,然后允许您将新的fielddata加载到缓存中。
Elasticsearch也建议尽可能使用Doc Values,因为它们的用途与fielddata相同。但是,因为它们存储在磁盘上,所以不依赖于JVM堆栈。尽管doc values不能用于分析字符串字段,但是在其他类型的字段上进行聚合或排序时,它们确实节省了fielddata的使用。在版本2.0之后的版本中,doc values在文档索引时自动创建,这大量减少了堆栈的占用。
Filter cache驱逐
如前所述,Filter缓存逐出指标只有在使用2.0之前的Elasticsearch版本时才可用。 每个segment都维护着自己的独立的filter cache。 由于在大的segement上比小的segment驱逐数据成本要高很多,因此没有明确的方法来评估每一次驱逐影响的严重程度。 但是如果您发现驱逐出现得更频繁,这可能表示您没有有效的利用filter——您可能只是频繁的创建新的filter并驱逐旧的filter,以至于完全无法使用缓存。 您可能想要调整您的查询(例如,使用布尔查询而不是and/or/not filter)。
挂起的任务(Pending tasks)
挂起的任务只能由master节点处理。这些任务包括创建索引并将分片分配给节点。挂起的任务按照优先级顺序处理——紧急优先,然后是高优先级的。当挂起的任务数量的变化值大于master节点处理速度时,他们便开始积累。如果这个指标持续增长的话,最好持续关注。 挂起的任务数量很好地反映了集群的运行情况。如果master节点已经非常繁忙,而挂起的任务还在持续增加,则可能导致群集不稳定。
失败的GET请求
GET请求比普通的搜索请求更直接——它根据ID检索文档。失败的get-by-id请求意味着没有找到对应的文档。您通常不会遇到这种类型的请求报错,但是在发生GET请求失败时关注一下还是有好处的。
结论
通过两期文章,我们介绍了Elasticsearch的一些最重要的方面,以便在集群增长和扩展您的集群时进行监控:
1. 查询和索引(indexing)性能
2. 内存分配和垃圾回收
3. 主机级别的系统和网络指标
4. 集群健康状态和节点可用性
5. 资源饱和度和相关错误
随着您监控Elasticsearch以及节点级别的系统指标,您将会发现哪些领域对于您的特定场景最有意义。