基于Elasticsearch的可观测系统,这样构建更高效更稳定!

2023-09-21 14:44:50 浏览数 (1)

在云原生时代,传统的监控系统由于缺乏对微服务之间的串联分析能力,逐渐被可观测系统取代。

可观测系统收集了来自不同微服务的可观测性数据例如日志、链路跟踪、指标以及事件数据等,并从全局的视角对整个业务系统提供观测能力,从而能快速在繁杂的微服务架构中发现异常,提升业务系统的稳定性和鲁棒性。

Elasticsearch(下文简称ES)是目前最受欢迎的一款企业级搜索引擎。

强大的分布式存储和分析能力使得ES不仅可作为需要全文检索的日志系统的首选,也可作为链路跟踪系统、指标系统以及事件中心的后端存储。在一般业务场景下,基于ES即可构造企业级的可观测系统。但随着数据量的增加,ES会出现读写变慢、成本增加等问题。

本文会基于ES的原理讨论优化ES的方法,期望可帮助读者提升基于ES的可观测系统的可用性和稳定性。

01

ES写数据原理与优化

ES默认每个节点都可作为协调节点接受客户端的读写请求。

当节点接收到一个写入请求时,会先根据写入数据判断是否需要执行pipeline预处理操作,再根据集群配置判断是否需要自动创建索引,然后计算分片路由,并将写入请求转发到索引主分片所在的节点上,等待实际执行写入节点的响应并返回给客户端。

索引的主分片所在的节点在收到写入请求后,会解析文档,根据索引配置更新索引mapping并计算文档的版本号。

上述操作执行完成后,ES会采用WAL技术,先将数据写入index buffer,再写入translog中,这两步是Elasticsearch保证数据近实时检索和高可用的关键。

index buffer是一片内存区域,在默认配置下ES每秒执行一次refresh操作将index buffer中的数据刷新到一个segment文件中。

经过refresh操作后的文档就可以被检索到,因此默认配置下ES的文档写入后约1秒就可被检索到,这就是ES近实时的实现。

segment文件并未真正落盘到磁盘中,而是保留在操作系统的page cache中,以减少I/O并提升写入性能。

因此当机器宕机后,有数据丢失的风险。

ES在写完index buffer后,会将文档再次写入translog。

translog文件通过flush操作被刷新到磁盘中持久化存储,translog文件刷新到磁盘的频率会显著高于segment文件刷新到磁盘的频率,ES从而基于translog实现了系统的高可用性。

文档在写入index buffer和translog之后,主分片所在的节点就会将写入请求发送到各个副本分片所在的节点,并等待副本分片节点执行完上述操作。

如果配置了参数index.write.wait_for_active_shards=1,那么主节点将不等待副本分片节点执行,直接向协调节点返回写入成功的响应。

上述写入流程概括如下图所示。

在了解ES的写入原理后,可发现在每个环节都可优化写入的效率。

首先客户端在发起写入请求时,建议通过bulk的方式批量提交写入文档,这样可减少与ES的连接数,并避免多个连接占用ES的线程池导致写入拒绝。

pipeline预处理操作是ES中耗费CPU较多的步骤,例如grok processor或script processor在大数据量场景下都会导致CPU使用率显著增加。

因此可将一些数据预处理的操作提前到客户端或Logstash中处理。

索引的创建和较重的操作,应该尽量避免写入自动创建索引,而是采用预创建索引的方式,先有索引再有写入。分片路由可能导致数据负载不均衡的情况,因此通常情况下建议使用ES默认路由规则。索引的大量mapping更新也会导致写入异常,因此尽量避免使用dynamic mapping配置。

ES默认的refresh操作是一秒执行一次,如果对检索时效性要求不高,可通过增加refresh_interval的值以达到减少refresh操作的频率的效果,从而减轻写入I/O的压力。

类似地,可通过增加index.translog.sync_interval的值减少translog文件刷新的磁盘中的频率。

增加分片的副本可提升数据的可用性,但也会加重写入的负担,因此一般配置1个副本即可,避免多副本写入带来的额外写入消耗。

02

ES读数据原理与优化

ES的查询分为两类,通过文档ID查询和通过Query匹配查询。

通过文档ID查询会先查询translog文件,若无匹配再查询segment文件。

通过Query查询则会直接查询segment文件。

客户端的查询请求会由接受请求的协调节点进行分析,并通过两阶段查询获取查询的结果。

两阶段查询称为query_then_fetch,第一阶段query查询匹配的文档ID,fetch阶段获得文档的内容。协调节点会在内存中维护一个优先级队列,对第一个阶段query查询获得的文档ID进行排序,计算得到最终返回客户端的文档ID后,再通过fetch阶段去丰富文档的内容。

在数据节点执行查询操作时,需要根据查询的字段遍历分片中的segment,并根据查询的配置选择查询倒排索引或者列存或者行存。

下图是ES查询原理的概览。

通过对ES查询原理的分析,可发现查询的性能与查询语法密切相关。

对于直接使用文档ID查询的场景,ES会先查询translog再查segment,效率相比直接查询segment会更高。

在使用Query查询时,由于会遍历segment进行查询,因此可根据经常查询的字段配置index sorting,在写入时对数据进行排序,在查询时就能加快segment遍历的速度。

在分页查询时,如果是深度分页的场景,应避免使用from与size组合的查询,而是采用scroll或search after操作避免大量内存消耗。

如果业务场景只需要获取少量字段,那么建议在查询时指定通过docvalue_fields获取数据,这是通过列存获取数据。相比通过原始数据或行存获取数据,获取少量字段使用列存能提升查询的性能。

对于全文检索的场景,由于写入的文档与查询的关键词都会进行分词,因此应尽量使用ES原生的分词器实现,避免自定义分词器导致ES消耗过多的CPU时间进行分词计算。

在聚合查询中,nested类型和join类型会有交较差的查询性能,因此在定义索引字段映射时应谨慎使用这两个类型的字段。

较深的嵌套查询会使得ES查询性能显著下降,因此建议拆分较深的嵌套查询。

03

ES架构原理与优化

ES集群是一个分布式系统,由多个节点构成。

每个节点上承载了数量相对均衡的分片,分片上存储了读写的文档。

ES节点主要可分为主节点、数据节点、Ingest节点、机器学习节点和协调节点。其中Ingest节点主要用于pipeline预处理,机器学习节点用于运行模型,数据节点用于文档读写,因此三种节点对内存和计算资源需求较高。而协调节点主要用于转发请求以及合并结果,因此资源的需求相对较少。主节点主要用于管理集群状态,资源需求更少。

在企业级环境中,通常不会单独配置协调节点,而是将任意节点都配置为拥有协调节点的角色。通常会配置3个专有主节点以提升系统的稳定性,专有主节点不负责与文档相关的预处理或读写操作,因此能有较高的稳定性。如果业务有大量的pipeline预处理操作,那么建议配置单独的Ingest节点用于计算,否则与协调节点类似,给既有节点添加Ingest角色即可。

ES是高内存消耗高I/O消耗的系统,大量的读写对内存和CPU都有较高的要求。推荐使用SSD磁盘以加快磁盘I/O。在实际场景中,需要密切关注ES集群各节点的内存、CPU和磁盘使用率,并及时横向或纵向扩容。ES有ILM功能,可方便地管理索引的生命周期。基于ILM功能,可将ES架构设计为热温冷架构,从而可在温层和冷层使用更低廉的硬件,减少ES集群的使用成本。

在可观测系统的实践中,如果是日志系统,由于业务日志通常的数据量较大,因此需要关注数据的保留市场,推荐使用ES的ILM功能管理索引。如果是指标系统或链路跟踪系统,数据通常是格式化的,且不需要全文分析,那么推荐关闭数据的原始数据存储和行存,仅保留列存,由此减少数据的存储量。可观测性数据是时序相关的数据,因此可使用ES的rollup功能进行数据的汇总,在时间维度上压缩数据,达到减少存储的目的。

04

总结

高可用性、高稳定性的可观测系统对业务排障和性能分析有重要的价值。

Elasticsearch作为当前主流的存储选型之一,是可观测系统实践中常用的组件。

本文简要介绍了Elasticsearch的读写原理和架构原理,并基于原理讨论了优化Elasticsearch的方法,希望能帮助读者构建更高效稳定的基于Elasticsearch的可观测系统。

0 人点赞