导语:本文详细介绍了 ElasticSearch 如搜索性能指标、索引性能指标、内存使用和垃圾回收指标等六类监控关键指标、集群和索引两类大盘配置示例,以及 ES 在查询性能差、索引性能差的两种典型问题场景下详细的原因、排查方式和解决方案,同时也介绍了如何通过 Prometheus 监控搭建可靠的监控系统,详尽全面,推荐给大家,也欢迎各位一起交流。
1. ElasticSearch 简介
1.1 概要
ElasticSearch (简称ES)是一个分布式、免费、开放的搜索和分析引擎,适用于所有类型的数据,包括文本、数字、地理空间、结构化和非结构化数据,最初由 Elastic 开发并开源。它本质上是一个分布式数据库,底层基于 Lucene 实现。ElasticSearch 屏蔽了 Lucene 的底层细节,提供了分布式特性,同时对外提供了 Restful API。ElasticSearch 以其易用性迅速赢得了许多用户,被用在网站搜索、日志分析等诸多方面。由于 ES 强大的横向扩展能力,甚至很多人也会直接把 ES 当做 NoSQL 来用。
1.2 特点
1.3 基本概念
ElasticSearch 是以集群的方式运行的,而节点是组成 ES 集群的基本单位,所以每个 ElasticSearch 实例就是一个节点,每个物理机器上可以有多个节点,使用不同的端口和节点名称。
节点按主要功能可以分为三种:主节点(Master Node),协调节点(Coordianting Node)和数据节点(Data Node)。
ElasticSearch 是一个分布式的搜索引擎,所以一般由多台物理机组成。而在这些机器上通过配置一个相同的 cluster name,可以让其互相发现从而把自己组织成一个集群。
索引可以存储大量的数据,可能会超过单个节点的硬件限制,而且会导致单个节点效率问题。ES 提供了将单个 Index 拆分到多个 Shard 上的能力,可以支持水平扩展,分布式和并行跨 Shard 操作(可能在多个节点),从而提高了性能和吞吐量。
为了避免故障导致节点及分片出现问题,ES 可以为分片设置副本(Replicas),副本通常在不同的节点上,从而保证高可用性。
Index(索引) 是具有稍微类似特征文档的集合,同在一个索引中的文档共同建立倒排索引。类似于 MySQL 中的 database 概念,但 ES 中的 Index 更加灵活,用起来也更加方便。提交给同一个索引中的文档,最好拥有相同的结构。这样对于 ES 来说,不管是存储还是查询,都更容易优化。
Document 的类型,类似于关系型数据库中的表的概念。该概念在6.X 时还可以使用,但在 Type 的概念已在7.X 开始废弃,官方认为这是个错误的设计。
文档是 ES 索引的基本单位,每个索引都是由数量众多的文档组成,Document 相当于传统数据库中的行,ES 中数据以 JSON 的形式来表示。
每个 Document 都类似一个 JSON 结构,它包含了许多字段,每个字段都有其对应的值,多个字段组成了一个 Document,可以类比关系型数据库数据表中的字段。
相当于数据库中的 schema,用来约束字段的数据类型,每一种数据类型都有对应的使用场景。mapping 中定义了一个文档所包含的所有 field 信息,每个文档都有映射。mapping 不是必须创建,因为 ES 中实现了动态映射。
添加 Index members 的 mapping:
PUT members
{
"mappings": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text"
},
"birthday": {
"type": "date"
}
}
}
}
在 Index members 中添加一个 Document:
{
"id": 10086,
"name": "法外狂徒张三",
"birthday": "1990-10-24T09:00:00Z"
}
1.4 基本概念
2. 监控关键指标
ElasticSearch 提供了大量的指标,可以用于监控各类故障现象:
2.1 搜索性能指标
ES 查询流程介绍
ES 查询可以分为两种:
检索策略可分为三大类:
QUERY_AND_FETCH:查询完就返回整个 Doc 内容,对应根据 ID 查询 Doc;
QUERY_THEN_FETCH:先查询出对应的 Doc id ,然后再根据 Doc id 匹配去对应的文档;
DFS_QUERY_THEN_FETCH:在 QUERY_THEN_FETCH 的基础上多了算分环节。
分布式场景下,查询通常分成两个阶段,以 QUERY_THEN_FETCH 为例子:
Query 阶段:
Fetch 阶段:
相关指标
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_indices_search_query_total | counter | 查询总数 吞吐量 |
2 | elasticsearch_indices_search_query_time_seconds | counter | 查询总时间 性能 |
3 | elasticsearch_indices_search_fetch_total | counter | 提取总数 |
4 | elasticsearch_indices_search_fetch_time_seconds | counter | 花费在提取上的总时间 |
5 | elasticsearch_indices_get_time_seconds | counter | GET请求总时间 |
6 | elasticsearch_indices_get_missing_total | counter | 丢失的文件的GET请求总数 |
7 | elasticsearch_indices_get_missing_time_seconds | counter | 花费在文档丢失的GET请求上的总时间 |
8 | elasticsearch_indices_get_exists_time_seconds | counter | 花费在文档存在的GET请求上的总时间 |
9 | elasticsearch_indices_get_exists_total | counter | 存在的文件的GET请求总数 |
10 | elasticsearch_indices_get_total | counter | GET请求总次数 |
2.2 索引性能指标
ES 的任意节点都可以作为协调节点(coordinating node)接受请求,当协调节点接受到请求后进行一系列处理,然后通过_routing 字段找到对应的 primary shard,并将请求转发给 primary shard, primary shard 完成写入后,将写入并发发送给各 replica, raplica 执行写入操作后返回给 primary shard, primary shard 再将请求返回给协调节点。大致流程如下图:
整体写入流程如下图所示:
说明
近实时性-refresh 操作:当一个文档写入 Lucene 后是不能被立即查询到的,ElasticSearch 提供了一个 refresh 操作,会定时地调用 Lucene 的 reopen (新版本为 openIfChanged)为内存中新写入的数据生成一个新的 Segment,此时被处理的文档均可以被检索到。refresh 操作的时间间隔由 refresh_interval 参数控制,默认为1s, 当然还可以在写入请求中带上 refresh 表示写入后立即 refresh,另外还可以调用 refresh API 显式 refresh。
merge 操作:由于 refresh 默认间隔为1s,因此会产生大量的小 Segment,为此 ES 会运行一个任务检测当前磁盘中的 Segment,对符合条件的 Segment 进行合并操作,减少 Lucene 中的 Segment 个数,提高查询速度,降低负载。不仅如此,merge 过程也是文档删除和更新操作后,旧的 Doc 真正被删除的时候。用户还可以手动调用 _forcemerge API 来主动触发 merge,以减少集群的 Segment 个数和清理已删除或更新的文档。
Translog:当一个文档写入 Lucence 后是存储在内存中的,即使执行了 refresh 操作仍然是在文件系统缓存中,如果此时服务器宕机,那么这部分数据将会丢失。为此 ES 增加了 Translog。
当进行文档写操作时会先将文档写入 Lucene,然后写入一份到 Translog,写入 Translog 是落盘的(如果对可靠性要求不是很高,也可以设置异步落盘,可以提高性能,由配置 index.Translog.durability 和 index.Translog.sync_interval控制),这样就可以防止服务器宕机后数据的丢失。由于 Translog 是追加写入,因此性能比较好。与传统的分布式系统不同,这里是先写入 Lucene 再写入 Translog,原因是写入 Lucene 可能会失败,为了减少写入失败回滚的复杂度,因此先写入 Lucene。
flush 操作:每30分钟或当Translog 达到一定大小(由index.Translog.flush_threshold_size 控制,默认512mb), ES 会触发一次 flush 操作,此时 ES 会先执行 refresh 操作将 buffer 中的数据生成 Segment,然后调用 Lucene 的 commit 方法将所有内存中的 Segment fsync 到磁盘。此时 Lucene 中的数据就完成了持久化,会清空 Translog 中的数据(6.x版本为了实现 sequenceIDs,不删除 Translog)。
根据上述流程可知,对于一个写入较为频繁的系统,refresh 和 flush 操作相关的指标较为重要,merge 相关的指标也需要关注,同时整个写入的耗时,搜索文档总数也需要关注,故而需要关注的写入相关指标为:
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_indices_indexing_index_total | counter | 被索引的文档总数 |
2 | elasticsearch_indices_indexing_index_time_seconds_total | counter | 索引文档花费的总时间 |
3 | elasticsearch_indices_refresh_total | counter | 索引refresh的总数 |
4 | elasticsearch_indices_refresh_time_seconds_total | counter | refresh索引总共话费的时间 |
5 | elasticsearch_indices_flush_total | counter | flush索引到磁盘的总数 |
6 | elasticsearch_indices_flush_time_seconds | counter | flush索引到磁盘的总花费时间 |
7 | elasticsearch_indices_merges_total | counter | Total merges(merge操作总次数) |
8 | elasticsearch_indices_merges_total_time_seconds_total | counter | 索引merge操作总花费时间 |
9 | elasticsearch_indices_merges_Docs_total | counter | merge的文档总数 |
10 | elasticsearch_indices_merges_total_size_bytes_total | counter | merge的数据量合计 |
11 | elasticsearch_indices_indexing_delete_total | counter | 索引的文件删除总数 |
12 | elasticsearch_indices_indexing_delete_time_seconds_total | counter | 索引的文件删除总时间 |
2.3 内存使用和垃圾回收指标
ES 是使用 Java 进行编写,运行在 JVM 之上,故而 ES 会以两种方式使用节点上的全部可用内存:JVM 堆和文件系统缓存(file system cache),因此,在 ES 运行期间,整个 JVM 的垃圾回收持续时间和频率将很值得监控。
相关指标:
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_jvm_gc_collection_seconds_sum | counter | JVM GC垃圾回收时间 |
2 | elasticsearch_jvm_gc_collection_seconds_count | counter | JVM GC 垃圾搜集数 |
3 | elasticsearch_jvm_memory_committed_bytes | gauge | JVM最大使用内存限制 |
4 | elasticsearch_jvm_memory_max_bytes | gauge | 配置的最大jvm值 |
5 | elasticsearch_jvm_memory_pool_max_bytes | counter | JVM内存最大池数 |
6 | elasticsearch_jvm_memory_pool_peak_max_bytes | counter | 最大的JVM内存峰值 |
7 | elasticsearch_jvm_memory_pool_peak_used_bytes | counter | 池使用的JVM内存峰值 |
8 | elasticsearch_jvm_memory_pool_used_bytes | gauge | 目前使用的JVM内存池 |
9 | elasticsearch_jvm_memory_used_bytes | gauge | JVM内存使用量 |
2.4 主机级别网络系统指标
主机级别资源及网络使用情况也需要关注。
相关指标
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_process_cpu_percent | gauge | CPU使用率 |
2 | elasticsearch_filesystem_data_free_bytes | gauge | 磁盘可用空间 |
3 | elasticsearch_process_open_files_count | gauge | ES进程打开的文件描述符 |
4 | elasticsearch_transport_rx_packets_total | counter | ES节点之间网络入流量 |
5 | elasticsearch_transport_tx_packets_total | counter | ES节点之间网络出流量 |
2.5 集群健康和节点可用性指标
ES 是按集群部署的,需要关注集群相关指标。
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_cluster_health_status | gauge | 集群状态,green( 所有的主分片和副本分片都正常运行)、yellow(所有的主分片都正常运行,但不是所有的副本分片都正常运行)red(有主分片没能正常运行)值为1的即为对应状态 |
2 | elasticsearch_cluster_health_number_of_data_nodes | gauge | node节点的数量 |
3 | elasticsearch_cluster_health_number_of_in_flight_fetch | gauge | 正在进行的碎片信息请求的数量 |
4 | elasticsearch_cluster_health_number_of_nodes | gauge | 集群内所有的节点 |
5 | elasticsearch_cluster_health_number_of_pending_tasks | gauge | 尚未执行的集群级别更改 |
6 | elasticsearch_cluster_health_initializing_shards | gauge | 正在初始化的分片数 |
7 | elasticsearch_cluster_health_unassigned_shards | gauge | 未分配分片数 |
8 | elasticsearch_cluster_health_active_primary_shards | gauge | 活跃的主分片总数 |
9 | elasticsearch_cluster_health_active_shards | gauge | 活跃的分片总数(包括复制分片) |
10 | elasticsearch_cluster_health_relocating_shards | gauge | 当前节点正在迁移到其他节点的分片数量,通常为0,集群中有节点新加入或者退出时该值会增加 |
11 | elasticsearch_breakers_tripped | counter | 熔断发生次数 |
12 | elasticsearch_breakers_limit_size_bytes | gauge | 熔断内存限制大小 |
13 | elasticsearch_breakers_estimated_size_bytes | gauge | 熔断器内存大小 |
2.6 资源饱和度和错误
ElasticSearch 节点使用线程池来管理线程如何消耗内存和 CPU,所以需要监控线程相关的指标。
序号 | 指标 | 类型 | 详情 |
---|---|---|---|
1 | elasticsearch_thread_pool_completed_count | gauge | 线程池操作完成线程数 |
2 | elasticsearch_thread_pool_active_count | gauge | 线程池活跃线程数 |
3 | elasticsearch_thread_pool_largest_count | gauge | 线程池最大线程数 |
4 | elasticsearch_thread_pool_queue_count | gauge | 线程池中的排队线程数 |
5 | elasticsearch_thread_pool_active_count | gauge | 线程池的被拒绝线程数 |
6 | elasticsearch_indices_fielddata_memory_size_bytes | gauge | fielddata缓存的大小(字节) |
7 | elasticsearch_indices_fielddata_evictions | gauge | 来自fielddata缓存的驱逐次数 |
3. 监控大盘
Prometheus 监控服务提供了开箱即用的 Grafana 监控大盘,根据预设大盘可以直接监控 ES 集群各类重要指标状态,能够进行问题的快速定位。本文集群大盘使用了腾讯云 ES 作为数据源,腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
3.1 集群大盘
集群大盘提供了集群相关的监控信息,包括了集群节点、分片、资源利用率、熔断、线程池等监控信息。
该监控提供集群概览信息,可大致概览集群状况,可以看出集群健康状况、节点数、数据节点、熔断器熔断次数、利用率、集群 pending 任务数、ES 进程打开的文件描述符等信息。集群健康监控 red 为1,green 时为5,yellow 为23。
分片监控提供集群中的主节点数、副本节点数,同时提供正在初始化的、正在迁移的、延迟分配的、未分配的分片信息。
该监控提供各类熔断器熔断的次数,以及熔断内存使用量。可以通过该监控去排查熔断发生的熔断器类别、熔断限制、熔断发生时的内存使用量以及是哪个节点发生的熔断。
节点监控提供了各节点的短期平均负载、CPU 使用情况、JVM GC 运行相关数据、数据存储使用情况、网络使用情况等。可以通过该监控发现并快速定位节点资源问题。
3.2 索引大盘
该监控提供 Translog 相关指标
4. 典型问题场景
4.1 ElasticSearch 查询性能差
ElasticSearch 查询性能变差的原因有很多,需要通过监控指标判断具体症状,然后根据症状进行相应处理。
每个分片都消耗资源(CPU/内存)。即使没有索引/搜索请求,分片的存在也会产生集群开销。
线程池中存在大量拒绝,从而导致查询不能被正常执行。
指标相关性表明,当集群不堪重负时,CPU 使用率和索引延迟都会很高。
在副本分片计数增加(例如,从1增加到2)后,可以观察到查询延迟。如果存在较多的数据,那么缓存的数据将很快被逐出,从而导致操作系统页面错误增加。
操作系统显示出持续的高 CPU/磁盘 I/O 利用率。停止第三方应用程序后,可以看到性能会提高。
4.2 ElasticSearch索引性能差
ElasticSearch 索引性能变差的原因同样有很多,具体情况具体分析。
硬件资源是一切的基础,其性能决定着运行在其上的集群的性能上限。
索引的分片、副本数及刷新时间间隔等均会影响索引性能。
集群的写入能力存在其上限,写入速度不能超过特定限制。
索引应该有数据上限,超过一定数量就会导致性能的大幅度下降。
实际使用中经常会出现,某些特定的业务使用较大,相应的索引负担就比较大了。
原因及处理同查询性能变差。
5. 监控系统搭建
5.1 自建 Prometheus 的痛点
5.2 腾讯云 Prometheus 监控接入
Prometheus 监控服务提供了基于 Exporter 的方式来监控 ElasticSearch 运行状态.
5.3 自建与腾讯云Prometheus监控对比
自建Prometheus | 腾讯云可观测平台Prometheus监控 | |
---|---|---|
成本 | 需自行配置和部署Prometheus及相关组件,采集组件需要自行扩缩容,运维成本高 | 开箱即用的Prometheus+Grafana+告警中心一体化平台,全托管,免运维 |
服务发现 | 自行配置,维护成本高 | 图形界面可直接选择需要上报的指标,大大降低维护复杂度 |
Grafana大盘 | 开源大盘信息较少,无法有效排查问题 | 专业的 ElasticSearch 监控大盘,方便用户快速定位问题及性能优化 |
告警 | 需要用户自行部署告警相关内容,且配置较为复杂 | 提供告警平台,同时提供清晰界面进行告警配置,简化操作 |
联系我们
如有任何疑问,欢迎扫码进入腾讯云可观测平台官方交流群~
关于腾讯云可观测平台
腾讯云可观测平台(Tencent Cloud Observability Platform,TCOP)基于指标、链路、日志、事件的全类型监控数据,结合强大的可视化和告警能力,为您提供一体化监控解决方案。满足您全链路、端到端的统一监控诉求,提高运维排障效率,为业务的健康和稳定保驾护航。功能模块有: