Elasticsearch是一个开源的分布式文档存储和搜索引擎,可以近乎实时地存储和检索数据结构,它很大程度上依赖于Apache Lucence--一个用Java编写的全文搜索引擎。
Elasticsearch以结构化JSON文档的形式呈现数据,并通过RESTful API和web客户端为PHP,Python和Ruby等语言提供全文搜索。Elasticsearch服务是具有弹性的,因为它易于水平扩展--只需添加更多节点即可分配负载。现在有很多企业动用它来动态存储,搜索和分析大量数据,包括维基百科,eBay,Github和Datadog。
在探讨性能指标之前,先来看看Elasticsearch的工作方式。在Elasticsearch中,集群由一个或多个节点组成,如下
每个节点都是单个Elasticsearch实例,其elasticsearch.yml
配置文件制定它属于哪个集群(cluster.name
)以及它是哪种类型的节点。配置文件中设置的任何属性(包括集群名称)也可以通过命令行参数指定。上图中的集群由一个专用主节点和五个数据节点组成。
Elasticsearch中最常见的三种类型的节点是:
node.data
为false
),来提高可靠性。在高使用率的环境中,将主节点和数据节点分开有助于确保总是有足够的资源分配给只有主节点可以处理的任务。node.master: false
来创建专用数据节点,来确保这些节点有足够的资源来处理与数据相关的请求,而无需处理集群相关管理任务的额外工作量。node.master
和node.data
设置为false
,那么该节点会成为一个客户节点,用作一个负载均衡器,以帮助路有索引和搜索请求。客户端节点可以承担一部分的搜索工作量,以便让数据节点和主节点可以专注于核心任务。根据使用情况,客户节点可能不是必须的,因为数据节点能够自行处理请求路由。但是,如果搜索|索引的工作负载足够大,可以利用客户节点来帮助路有请求。在Elasticsearch中,相关数据通常存储在同一个索引中,可以将其视为配置逻辑包装的等价物。每个索引都包含一组JSON格式的相关文档。Elasticsearch的全文索引使用的是Lucence的倒排索引。为文档创建索引时,Elasticsearch会自动为每个字段创建倒排索引;倒排索引将字段映射到包含这些字段的文档。
索引存储在在主分片(一个或多个)和副本分片(零个或多个)中,每个分片都是一个Lucence的完整实例,可以当成一个迷你搜索引擎。
当创建索引时,可以制定主分片的数量以及每个主分片的副本数量。默认值为每个索引五个主分片,每个主分片一个副本。在索引被创建后,主分片的数量无法更改,因此在选择数量时要谨慎,否则后面可能需要重新建立索引。副本的数量可以在后面根据需求更新。为了防止数据丢失,主节点确保每个副本分片不会和主分片分配到同个节点上。
Elasticsearch提供了大量指标,可以帮助用户检测出故障迹象,并在遇到诸如不可靠节点,内存不足和GC时间过长等问题时采取措施。一些需要监控的关键指标是:
上面列出的指标都可以通过Elasticsearch的API以及像Elastic的Marvel这样的工具收集到。
搜索请求和索引请求是Elasticsearch中的两个主要请求类型。在某种程度上,这些请求和传统数据库系统中的读取和写入请求很类似。Elasticsearch提供了与搜索过程的两个主要阶段(查询和提取)相对应的指标。一次搜索请求从开始到结束的路径如下
当Elasticsearch主要用于搜索时,有必要监控查询延迟并在超过阙值时采取措施。监控有关查询和提取的相关指标非常重要,这些指标可以帮助确定在一段时间内的搜索性能。比如,可以跟踪查询请求中的峰值和长期的的增长趋势,以准备优化配置来获得更好的性能和可靠性。
指标描述 | 指标名 | 指标类型 |
---|---|---|
query总数 | indices.search.query_total | 吞吐量 |
query总耗时 | indices.search.querytimein_millis | 性能 |
当前在处理的query数量 | indices.search.query_current | 吞吐量 |
fetch总数 | indices.search.fetch_total | 吞吐量 |
fetch总耗时 | indices.search.fetchtimein_millis | 性能 |
当前在处理的fetch数量 | indices.searchfetchcurrent | 吞吐量 |
Query 负载:监控当前正在进行的query数量可以大致了解集群在任何特定时刻处理的请求数量。可以考虑在出现异常尖峰和骤降时发出警告。
Query延迟:尽管Elastisearch没有明确提供这个指标,但是可以用现有指标来推算这个值,算法是定期用查询总数除以总耗时。
Fetch延迟:搜索的第二阶段(fetch阶段)通常比query阶段耗时要少。如果这个值持续增加,可能意味着磁盘速度慢,或者请求的结果数量过多。
索引请求类似于传统数据库系统中的写请求。如果Elasticsearch集群主要用于索引,那么对索引性能的监控是非常有必要的。在讨论监控指标前,我们先看看Elasticsearch处理索引的方式。当在索引中添加新信息或者删除现有信息时,索引中的每个分片都会通过两个步骤更新:refresh和flush。
新加入到索引的文档不能立即用于搜索,这些文档会先被写入内存缓冲区,等待下一次索引刷新,默认情况下每秒刷新一次。refresh先从之前内存缓冲区中创建新的内存段,让这些内容能够被搜索到,然后清空缓存区,过程如下
索引的分片由多个段组成。这个Lucene的核心数据结构,一个段实际上索引的变更集。每个段使用文件,内存和CPU,为了有效利用这些资源,这些段在每次刷新时创建,随后合并。
段是微型的倒排索引,可以将词映射到包含这些词的文档。每次搜索索引时,依次搜索主分片或者副本分片,在分片中搜索每个分段。
段是不可变的,所以更新文档会:
当过期段与另一个段合并时,最终会删除旧信息。
在将新索引文档添加到内存缓冲区的同时,这些内容也会添加到分片的translog,translog用于持久记录操作的日志。每隔30分钟,或者当translog大小到达最大时(默认是512MB),会触发一次flush操作。在flush期间,内存缓冲区的任何文档都会刷新(存储在新段中),所有内存中的段都会提交到磁盘,同时translog被清空。
translog有助于防止节点故障时丢失数据。可以用translog帮助恢复可能在刷新之间丢失的操作。日志每5秒提交到磁盘;或在索引,删除,更新或批量请求成功后,日志提交到磁盘。流程如下
Elasticsearch提供了很多有关索引的指标
指标描述 | 指标名 | 指标类型 |
---|---|---|
索引的文档总数 | indices.indexing.index_total | 吞吐量 |
索引文档总耗时 | indices.indexing.indextimein_millis | 性能 |
当前索引的文档数 | indices.indexing.index_current | 吞吐量 |
索引refresh总数 | indices.refresh.total | 吞吐量 |
refresh总耗时 | indices.refresh.totaltimein_millis | 吞吐量 |
索引flush到磁盘总数 | indices.flush.total | 吞吐量 |
flush总耗时 | indices.flush.totaltimein_millis | 吞吐量 |
索引延迟:Elasticsearch并不直接提供这个指标,不过可以根据index_total
和index_time_in_millis
算出来。如果注延迟增加,可能是因为一次索引的太多文档(Elastisearch建议批量索引大小为5MB-15MB)。
如果计划索引大量文档,并且不需要新的信息可立即用于搜索,可以通过降低刷新频率来优化索引性能而不是搜索性能,直到完成索引。
Flush延迟:由于数据在成功完成刷新之前不会持久保存到磁盘,因此跟踪刷新延迟并在性能开始下潜时采取措施会很有用。如果看到此指标稳步增加,则可能表示磁盘速度较慢;此问题可能会升级并最终阻止向索引添加新文档。在这种情况下,可以尝试降低index.translog.flush_threshold_size
,此设置确定在触发刷新之前translog大小可以达到的大小。如果Elasticsearch写比较重,可以考虑使用iostat
关注磁盘I/O。
内存是需要监控的关键指标之一。Elasticsearch和Lucene以两种方式利用节点上的所有可用内存:JVM堆和文件系统缓存。Elasticsearch在Java虚拟机(JVM)中运行,这意味着JVM垃圾收集的持续时间和频率也是需要监控起来的。
使用Elasticsearch需要设置适当的JVM堆大小。一般来说,Elasticsearch的经验法则是将不到50%的可用RAM分配给JVM堆,永远不会高于32GB。分配给Elasticsearch的堆内存越小,Lucene可用的内存就越多,而Lucene很大程度上依赖于文件系统缓存来快速响应请求;但是也不能设置的太小,因为可能会遇到内存不足,或者因为频繁GC导致吞吐量降低。这篇博客有详细描述。
Elasticsearch默认设置JVM堆大小为1G,在大多数场景下这个都太小,可以所需要的堆大小导出为环境变量,然后重新启动Elasticsearch。
export ES_HEAP_SIZE=10g
Elasticsearch依赖于垃圾收集(GC)进程来释放堆内存。需要留意GC的频率和持续时间。将堆设置得太大会导致垃圾收集时间过长;这些过度暂停是危险的,会导致集群中其他节点认为该节点失去响应。
指标描述 | 指标名 | 指标类型 |
---|---|---|
年轻代垃圾回收总数 | jvm.gc.collectors.young.collection_count | |
年轻代垃圾回收耗时 | jvm.gc.collectors.young.collection_time_in_millis | |
年老代垃圾回收总数 | jvm.gc.collectors.old.collection_count | |
年老代垃圾回收耗时 | jvm.gc.collectors.old.collection_time_in_millis | |
当前JVM堆占比 | jvm.mem.heap_used_percent | |
已提交的JVM堆量 | jvm.mem.heap_committed_in_bytes |
在使用的JVM堆: Elasticsearch设置为在JVM堆使用率达到75%时启动垃圾回收。监视哪些节点表现出高堆使用率并设置警报以查明是否有任何节点始终使用超过85%的堆内存可能很有用:这表明垃圾收集的速度跟不上垃圾创建的速度。要解决这个问题,可以增加堆大小,或者通过添加更多节点来扩展群集。
已使用的堆和已提交的堆:使用的堆内存量通常采用锯齿模式,当垃圾堆积时会上升,当收集垃圾时会下降。已使用堆和已提交堆比例增加时,意味着垃圾收集的速率跟不上对象创建的速度,这可能导致垃圾收集时间变慢,并最终导致OutOfMemoryErrors。
GC持续时间和频率:回收年轻代和年老代垃圾回收都会经历“世界停止”阶段,因为JVM停止执行程序来进行回收。在这段时间内,节点无法完成任何任务。主节点会每隔30秒检查其他节点状体啊,如何任何节点的垃圾回收时间超过30秒,主节点将认为这个节点已经挂掉。
内存使用率:如上所述,Elasticsearch充分利用了尚未分配给JVM堆的任何RAM,其依靠操作系统的文件系统缓存来快速可靠地处理请求。有许多变量决定Elasticsearch是否成功从文件系统缓存中读取。如果段文件最近由Elasticsearch写入磁盘,则它已在缓存中;但是,如果节点已关闭并重新启动,则第一次查询段时,很可能必须从磁盘读取信息。这是需要为什么确保集群保持稳定并且节点不会崩溃的重要原因之一。
I/O:在创建,查询和合并段时,Elasticsearch会对磁盘进行大量写入和读取操作。对于具有持续经历大量I / O活动的节点的大量集群,Elasticsearch建议使用SSD来提高性能。
CPU使用率:可视化CPU使用率会很有用。CPU使用率增加通常是由大量搜索和索引请求导致。
网络流出/流入字节数:节点之间的通信是平衡群集的关键。除了Elasticsearch提供有关群集通信的传输指标,还可以查看网卡发送和接收的字节速率。
打开文件数:文件描述符用于节点到节点通信,客户端连接和文件操作。如果此数字达到系统的最大容量,则在旧的连接关闭之前,将无法进行新的连接和文件操作。
指标描述 | 指标名 | 指标类型 |
---|---|---|
集群状态 | cluster.health.status | |
节点数量 | cluster.health.number_of_nodes | 可用性 |
初始化中的分片数 | cluster.health.initializing_shards | 可用性 |
未分配分片数 | cluster.health.unassigned_shards | 可用性 |
集群状态:如果群集状态为黄色,则至少有一个副本分片未分配或丢失。搜索结果仍然完整,但如果更多分片消失,可能会丢失数据。
红色群集状态表示至少缺少一个主分片,并且数据正在丢失,这意味着搜索将返回部分结果。
初始化中和未分配的分片:首次创建索引或重新启动节点时,其主机节点尝试将分片分配给节点时,其分片将在转换为“已启动”或“未分配”状态之前暂时处于“初始化”状态。如果发现分片在初始化或未分配状态下保留的时间过长,则可能表示集群不稳定。
在这篇文章中,我们介绍了Elasticsearch的一些最重要的领域,以便在扩展和扩展集群时对其进行监控。
在监视Elasticsearch指标以及节点级系统指标时,可以集合具体的使用场景挑选出最重要的指标。