ElasticSearch多集群构架实战

探讨了Elasticsearch单集群的瓶颈与挑战,介绍了多集群架构的优势与实施方案,包括TribeNode的使用、集群类型划分及自动化部署,以及面对多集群配置、版本统一和容量均衡的挑战所采取的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单集群构架瓶颈:
在这里插入图片描述
单集群构架,写入和查询分别通过Sink服务和Gateway服务管控起来。

Sink服务:
所有的写入ElasticSearch的数据都是经由Kafka消费入到ElasticSearch。
Kafka业务数据包括 log数据,Binlog数据和业务自主上报数据,Sink服务将这些数据实时消费入到ElasticSearch
Sink服务设计是想对写入ElasticSearch集群进行管控,保护ElasticSearch集群,防止海量的数据写入拖垮ElasticSearch
可以从Kafka或者Mq实时同步数据到ES,HDFS,Ceph等多个存储服务。

有了多集群构架后,ElasticSearch平台可以消费一份MQ数据写入多个ElasticSearch集群,做到集群级别的容灾,还能通过MQ回溯数据进行故障恢复。

Gateway服务:
所有业务查询都是经过Gateway服务,Gateway服务实现了ElasticSearch的Http Restful和TCP协议。
业务放可以通过ElasticSearch各版本语言的SDK直接访问Gateway服务,Gateway服务还实现了SQL接口,业务可以直接使用sql来访问Elasticsearch平台。

Gateway 服务最初提供了应用权限的管控,访问记录,限流、降级等基本能力,后面随着平台演进,Gateway 服务还提供了索引存储分离、DSL 级别的限流、多集群灾备等能力

Admin服务
整个ElasticSearch平台由Admin服务统一管控起来。Admin服务提供了索引的生命周期管理,索引容量自动规划,索引健康区分,集群监控等丰富的平台能力,以及Sink,Gateway服务提供索引,权限等元数据信息。

ES单集群瓶颈:
集群越来越大,当集群共有3000+索引,超过了50000个Shard,集群总容量达到了PB级别。

风险主要来自于一下3个方面:
ElasticSearch构架瓶颈
索引资源共享风险
业务场景差异大

ElasticSearch构架瓶颈
ES看起来是个p2p构架,但实际上,仍然是中心化的分布式架构。
整个集群只有一个Active Master。Master负责整个集群的元数据管理。
集群所有的元数据保存在ClusterState对象中,主要包括全局的配置信息,索引信息和节点信息。只要元数据发生修改,都得由Master完成。

ElasticSearchMaster的任务处理是单线程完成的,每次处理任务,涉及到ClusterState的改动,都会将最新的ClusterState对象Publish给集群的全部节点,并阻塞等待全部节点接受的变更消息,处理完变更任务后,才完成本次任务。

这样的构架模型导致在集群规模变大的时候,会出现很严重的稳定性风险:

  • 如果有节点假死,比如JVM内存被打满,进程还存活着,响应Master任务时间会很长,影响单个任务的完成时间。
  • 有大量恢复任务的时候,由于Master是单线程处理的,所有任务需要排队处理,产生大量的pending_tasks。恢复时间变得很长。
  • ElasticSearch的任务分了优先级,例如put-mapping任务优先级低于创建,恢复索引,如果一些业务上低优先级索引在恢复,正常索引有新字段写入时候会被阻塞。
  • Master任务处理模型,在任务执行完成后,会回调大量的Listener处理元数据变更。其中有些回调逻辑在索引,Shard膨胀后,会出现缓慢问题,当Shard膨胀到5-6w时,一些任务处理需要8-9s时间,严重影响了集群的恢复能力。

对这些问题,ElasticSearch也在不断优化,针对相同类型的任务,比如put-mapping任务,Master会一次性处理所有堆积在队列里的相同任务。

ClusterState对象只传递diff内容,优化回调Listener模块的处理耗时环节等等。
但是由于整个集群任务都集中在一个Master的一个线程中处理,在线程中需要同步元数据变更给集群的每个节点,并阻塞等待全部节点同步完成。这个模型在集群规模不断膨胀时,稳定性会不断下降。

索引资源共享风险
ElasticSearch索引是由多个Shard(分片)组成,Master会动态给这些Shard分配节点资源,不同的索引会存在资源混用的情况。
在这里插入图片描述
ElasticSearch通过 Shard Allocation Awareness的设计,可以将集群的节点按照集合划分成不同的Rack。
在分配索引时可以指定Rack列表,这样索引就只会分配在指定Rack对应的节点列表,从而做到物理资源的隔离。

但是实际使用中,很多容量小的索引由于占用资源有限,会混在一些节点中,这种情况下,会因为个别索引的查询,写入量飙升,而影响到其他索引的稳定性。如果出现了节点故障,就会影响到整个集群的稳定性。

业务场景差异大
ElasticSearch适用的业务场景差异特别大:

  • 针对线上核心入口搜索,一般按城市划分喉,索引容量不大,数据没有实时写入or实时写入TPS很小
  • 针对日志检索的场景,实时写入量特别大,有些索引甚至超过了100w/s的TPS,该场景对云余量要求很高,但对QPS和查询RT要求不高
  • 针对Binlog数据的检索,写入量相比日志会小很多,但是对查询的复杂度,QPS和RT有一定的要求
  • 这对监控,分析类的场景,聚合查询需求会比较多,对ElasticSearch内存压力比较大,容易引起节点的抖动和GC。

这些场景个亿,稳定性,性能要求各不相同,一个ElasticSearch集群即使使用各种优化手段,很难全部满足需求,最好还是按照业务场景划分ElasticSearch集群

多集群挑战
最大挑战在于查询方式的兼容。ElasticSearch查询索引方式很灵活,可以支持 * 号作为通配符匹配
这样一个索引Query可能查询的是多个索引,比如有如下 3 个索引:

index_a
index_b
index_c

使用 index* 查询的时候,可以同时查询到 index_a、index_b、index_c 三个索引。
Elasticsearch 这种实现方式非常简单,由于一次 Query 最终查询的是多个 Shard 的数据。
所以无论对于具体的索引,还是模糊的索引,都是先根据索引名称得到 Shard 列表,再将多个 Shard 的 Query 结果 Merge 到一起返回。
这样的使用方式,对于多集群方案就会遇到问题,比如index_a在A集群,index_b在B集群,index_c在C集群,对于index*的Query,就无法在一个集群上完成。

Tribenode介绍
特性可以很好的满足多集群查询的特性
Trienode 中org.elasticsearch.tribe包下只有三个文件,核心类是TribeService
TribeNode的核心原理就是Merge每个集群的ClusterState对象成一个公共的ClusterState对象,ClusterState包含了索引,Shard和节点数据分布表。
由于ElasticSearch的工作逻辑都是基于ClusterState元数据驱动的,所以对外看起来就是一个包含全部索引的ClientNode。

在这里插入图片描述
Tribenode通过配置多个ElasticSearch集群地址,然后以ClientNode角色分别连接每个集群,每个集群看起来会多了一个ClientNode
TribeNode通过该ClientNode角色获取到集群的ClusterState信息,并绑定listener监听ClusterState变化。
TribeNode将所获取的所有集群的CLusterState信息Merge到一起,形成一个对外部访问使用的Cluster对象,对外提供服务。
Tribenode 除了注册 Listener 和 Merge ClusterState,其他的所有逻辑都是复用了 Clientnode 的代码。

优点:
能够满足多集群访问的需求,对外使用是透明的。
实现的简单、优雅,可靠性有保证。
不足:

  • Tribenode 必须以 Clientnode 加入到每个 Elasticsearch 集群,Master 的变更任务必须等待 Tribenode 的回应才能继续,可能影响到原集群的稳定性。
  • Tribenode 不会持久化 ClusterState 对象,重启时需要从每个 Elasticsearch 集群获取元数据。而在获取元数据期间,Tribenode 就已经能够提供访问,会导致查询到还在初始化中的集群索引访问失败。
  • Tribenode 连接的集群多了,初始化会变得很慢。针对该缺陷,我们平台在重启某个 Tribenode 集群时,将 Gateway 访问该集群的全部流量切到备份 Tribenode 集群解决。
  • 如果多个集群有相同的索引名称,Tribenode 只能设置一种 Perfer 规则:随机、丢弃、Prefer 指定集群。这可能带来查到不符合预期的异常。
  • Elasticsearch 平台通过统一管控索引,避免了同一个索引名称出现在 Tribenode 连接的多个集群中。

多集群架构拓补:
在这里插入图片描述
平台将 Elasticsearch 集群划分成四种类型:
Log 集群、
Binlog 集群、
文档数据集群、
独立集群。
公共集群一般最多 100 台 Datanode 为基准组成一个集群

集群的自动化部署和弹性扩缩容,可以很方便的水平扩展集群,Elasticsearch 集群前面是多组 Tribenode 集群,主要是为了解决 Tribenode 的稳定性问题。

Gateway 会同时连接 Tribenode 集群和 Elasticsearch 集群,根据应用访问的索引列表,配置应用访问的集群名称
Gateway 根据集群名称,将请求代理到指定集群访问,如果访问的是 Tribenode 集群,则该应用可以访问到多个集群的索引
Admin 服务则管控了所有的 Elasticsearch 集群,以及索引和集群的对应关系。一系列功能都针对多集群做了改造
Sink 服务已经从 Elasticsearch 平台分离出去,成立 DSink 数据投递平台
DSink Manager 负责管理 DSink 节点,DSink Manager 从 Elasticsearch Admin 服务获取索引的元数据信息,下发给对应的 DSink 节点

收益:

  • Elasticsearch 平台的隔离性可以从物理节点级别上升到 Elasticsearch 集群级别。对于核心的线上应用,可以使用独立的 Elasticsearch 集群支持
  • 不同类型的数据按集群划分,避免相互影响,减小了故障的影响面,对平台稳定性带来极大的提升
  • Elasticsearch 平台的扩展能力进一步提升,通过新增集群可以很好的做到水平扩展
  • 多集群架构最终做到了对业务方无感知,业务看起来,Elasticsearch 平台就像一个无限大的 Elasticsearch 集群,而无需感知索引真实的集群分布

多集群架构实践经验:
滴滴 Elasticsearch 平台多集群的架构已经演进了一年半时间,这期间也遇到一些多集群架构带来的挑战。

①Tribenode 稳定性挑战

随着集群数量越来越多,前面提到的 Tribenode 不足越来越明显,比如初始化的时间越来越长等等。

我们采取的应对策略是部署多组 Tribenode 集群,有几组连接全量的集群,互为灾备,有几组只连接核心的一些集群,用作更为重要的跨集群访问场景。

Tribenode 的 ClusterState 元数据包含了太多的索引和 Shard,Elasticsearch 的 Search 逻辑在有些 Case 处理下容易出现耗时过长的情况。

Elasticsearch 在 Client 接收到 Search 请求时,是在 Netty 的 IO 线程中完成请求转发给每个 Shard 的,低版本的 Elasticsearch 还没有限制一次 Query 的 Shard 数量。

在一些复杂的模糊索引匹配 Shard 的逻辑中,以及给每个 Shard 发送 Query 请求时,会出现较高的耗时,可能有超过 1-2s 的 Case,这会影响到该 Netty Worker 上的其他的请求,造成部分响应飙高的情况。

我们优化了 Tribenode Search 流程中一些索引、Shard 膨胀之后的耗时逻辑,解决了该问题。

②多集群配置、版本统一的挑战

在只有一个集群的时候,平台只用维护一份集群的配置和版本。当集群数量增多后,不同集群间的 _cluster settings 信息会出现部分差异。

这些差异,可能会导致集群间的负载不均,恢复速度过快或者过慢等问题,每个集群还有一份基础的索引模板配置,这里面也出现了部分差异。

这个问题目前我们还在解决中,我们计划将 Admin 服务分离成索引管理服务和集群管理服务,集群管理会专注于集群版本、配置、部署、扩容、监控等方面对 Elasticsearch 集群进行更全面的管控。

我们做的一些 Elasticsearch 源码优化,会先后在部分集群上线,这样导致了集群间的版本混乱的问题。

我们的解决方案是在 Elasticsearch 和 Lucene 内增加内部的版本号,通过公司内部的发布系统,发布 Elasticsearch 的更新,后续集群管理服务会将集群的版本管理起来。

③多集群间容量均衡的挑战

我们主要从跨集群索引迁移和容量规划解决集群间容量均衡的挑战,在单 Elasticsearch 集群的时候,数据迁移可以依赖 Elasticsearch 的 Rebalance 能力完成。

在使用多集群架构后,平台内部的 Elasticsearch 集群会出现资源分配不均的问题。

例如有些索引容量增长的很快,导致所在集群的资源紧张,有些索引数据减少,不需要占用太多资源,导致集群资源空闲。

于是产生了索引跨集群迁移的需求。针对这个需求,我们通过给索引添加版本号,解决了索引跨集群迁移问题。之后我们有文章会详细的介绍该方案。

滴滴 Elasticsearch 平台实现了索引容量的自动规划,解决了集群间的容量均衡。

Elasticsearch 平台可以动态的规划索引的容量。当一个集群容量规划不足时,平台可以动态的迁移一部分索引到空闲的集群中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值