ElasticSearch大集群管理维护的难题与个推GProxy解决方案

标签: elasticsearch 集群 管理 | 发表时间:2020-10-07 16:40 | 作者:个推开发者
出处:https://juejin.im/backend

前言

用户搜索组件和日志管理平台是个推推送服务的重要组成部分。ElasticSearch(简称ES)作为一个开源的分布式搜索引擎,能较好地满足上述要求。个推在ES的使用上经过了多年迭代,积累了丰富的经验,特别是在数据量不断增大时,如何管理集群、维护集群稳定、优化集群性能,我们进行了许多实践。

本文将从三部分讲述个推ElasticSearch架构的演变过程:大集群的挑战、GProxy如何支持多集群以及当前运行情况。

作者| 个推平台研发总监 逍遥 &高级Java工程师 南洋

01

个推ES服务概述

个推使用ES的业务场景主要是对用户信息增删改查和日志存储,是支持个推推送的核心服务之一,其特点是:

● 数据更新快:需要实时更新用户画像等信息

● 查询条件复杂:支持多种维度交并补,组合条件搜索

● 查询数据量大:一个推送任务可能会需要查询千万级的数据

我们选择ES的原因主要有三:

● 提供近实时索引,最短可以在1s内搜索到写入的文档

● 能够支持复杂条件的查询,满足我们各种检索条件的需求

● 分布式特性能够较好地满足水平扩容和高可用的要求

此外,ES官方和社区都非常活跃,周边的生态产品也多,遇到问题基本能够很好地得到解决。

02

大集群的挑战

个推集群演进

上图展示的是个推ES集群演进的过程。个推使用ES时间较早,起初从0.20.x版本开始用,当时集群规模较小,后来为了scroll查询结果不带source,进行了index-source的分离,升级到了0.90.x版本。接着官方推出了支持无source查询功能的1.2.0版本,我们又进行了集群合并。随后,为了使用官方的一些新特性,我们升级到了1.4.x和1.5.x版本。

此时,集群规模已经很大了,升级一次版本比较不方便,而且后续的新特性对我们没有很强的吸引力,于是很长时间没升级,跳过了官方推出的2.x版本。但集群由于规模大,开始出现很多难以解决的问题,需要进行拆分升级,并且官方版本也更新到了5.x版本,不支持直接从1.x升级5.x,于是我们考虑用数据网关的方式解决升级、重启的困难,集群也演化到了上图的最后一版架构。

大集群的问题

大集群还带来很多问题,以下是我们在使用过程中遇到相对比较棘手的几个问题。

● 第一个问题是JVM内存容易居高不下。

ES内存的占用主要有几个部分:Segment Memory、Filter Cache、Field Data cache 、Bulk Queue、Indexing Buffer和Cluster State Buffer 。Segment Memory会随着段文件增长而增长,大集群这块内存占用没法避免。

Filter Cache和Field Data cache个推用到的场景不多,我们便通过参数配置予以禁用。Bulk Queue和Indexing Buffer都比较固定,内存不会不断增长,也没必要调整参数。Cluster State Buffer是当时比较棘手的一个问题,我们设置mapping的方式是在config目录下配置default_mapping.json文件,该文件会匹配所有写入的文档,进行格式解析处理,ES处理解析过之后会在内存中缓存一份ParserContext。而由于type数不断增加,这部分内存占用会越来越多,直到耗尽,如果不索引新type,则不会增长。

在出现内存居高不下的问题时,我们分析了它的dump文件,如下图,发现是ParserContext占用导致的。当时没有很好的办法彻底解决,只能采用重启的方式清空ParserContext,暂时缓解一段时间。但随着文档的不断写入,这部分内存占用还是会重新变大。

![](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)

● 第二个问题是超大分片和超大段。

我们默认使用docid作为routing的依据,通过hash算法将文档散列到不同分片上。这种方式在文档数少的时候分片大小还比较均匀,但当文档数涨到了一定程度时,分片的大小差距会变大。在每个分片平均100g大小的时候,差距最大可达20g。此时,达到最大段阈值限制的段数量也非常多,这导致在段合并的时候比较耗时。

● 第三个问题是磁盘IO高。

我们经常使用scroll查询文档,超大的段文件会导致文件磁盘查找效率降低。并且机器内存被ES节点的JVM占用了大半,致使文件系统很难使用内存缓存段文件页。这就导致scroll查询会直接读取磁盘文件,IO被打满。从监控看,集群的IO基本是时刻处于满的状态。

此外还有许多隐患。

首先是扩展瓶颈,集群预设的分片数原本是较充裕的,然而在经过多次扩容后,实例数已经和分片数相等了,扩容实例后,集群也不会将分片分配到新实例。其次是原先机器的磁盘空间逐渐不足,ES默认水位线是85%,到达后分片就会开始乱跳难以恢复。

然后是调整难,重启恢复非常慢,如果升级重建,索引也很慢。

最后集群的健壮性也会受到影响。文档数变大,压力也会变大,更容易出现故障,某个实例故障后压力会分摊给其他节点,业务会产生感知。

03

GProxy的解决方案

对于上面描述的这些问题,我们希望找到一个解决方案能够提供如下功能:

1、能够平滑升级集群版本,并且升级期间不影响业务使用

2、通过拆分大集群为小集群,使业务分流,减轻集群压力

3、提供集群数据的多IDC热备,为异地多活提供数据层支持

但是之前的架构中,业务服务直接访问ES集群,耦合严重,要实现这些需求就变得比较困难。于是,我们选择了proxy-based架构,通过增加中间层proxy来隔离存储集群和业务服务集群,为更灵活的运维存储集群提供支持。

![](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)

上图是GProxy的整体架构,它是一个三层架构:

● 最上层是业务层,只需和 proxy 交互,通过etcd实现proxy的服务发现

● 中间是GProxy层,提供请求转发和集群的管理

● 最下方是多个ES集群

GProxy包含了多个组件:

● etcd:高可用的元信息存储数据库,包括路由规则、集群信息、proxy服务地址、迁移任务等

● sdk:扩展了es原生sdk,通过其sniffer机制,封装了对proxy服务发现和熔断等功能

● proxy是一个轻量级的代理服务,扩容很方便,启动后可以将自己的地址注册到etcd中

● dashboard 是整个集群的管理服务,并提供 web 界面,方便运维人员对集群进行管理和监控

● migrate服务提供不同集群间的迁移功能

服务发现和路由规则

有了上面的总体架构后,还需要解决两个问题:

1、业务服务如何发现proxy,也即服务发现问题

2、 proxy将请求转发给哪一个集群,也即路由问题

服务发现

etcd是一个高可用的分布式键值数据库,且通过http api进行交互,操作简便,因此我们选择etcd来实现服务发现和元数据存储。

proxy是一个无状态的服务,启动初始化完成之后,将自己的地址注册到etcd中。通过etcd的lease机制,系统可以监控proxy的存活状态。当proxy服务出现异常而不能定时续期lease时,etcd会将其摘除,避免其影响正常的业务请求。

ElasticSearch提供的sdk预留了sniffer接口,sdk可以通过sniffer接口来获取后端地址。我们实现了sniffer接口,其定期从etcd获取proxy列表,并通过etcd的watch机制,监听服务的上下线,及时更新内部的连接列表。业务方还是可以按原来的方式使用原生的sdk,不需要过多的改动,只需要将sniffer注入到SDK就行。

路由规则

在个推推送业务场景中,每个app推送需要的数据都可以视为是一个整体,因此我们选择按照app的维度进行请求的路由,每个app推送所需的数据都存储在一个集群内。

路由信息保存在etcd中,格式是 appid->clusterName 这样一个对应关系。如果没有这样一个对应关系,proxy会将appid归属到一个默认集群。

proxy启动时会拉取最新的路由表,并通过etcd的watch机制,监控路由表的变更。

![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1719c44665034bd9801468a4c3b5b4ad~tplv-k3u1fbpfcp-zoom-1.image)![](data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)

路由关系的变更通过迁移操作实现,以下是迁移流程的介绍。

迁移流程

每个app都属于一个集群。当集群的负载不均衡时,管理员可以按照app维度,通过迁移服务进行集群间的数据迁移。

迁移流程包含两个步骤:数据同步和路由规则的修改。数据同步需要同步两份数据:全量数据和增量数据。

1、全量数据通过ElasticSearch的scroll api导出

2、因为ElasticSearch没有提供增量数据的获取方式(类似mysql的binlog协议来实现增量数据的获取),因此我们通过proxy双写来实现增量数据的获取。

迁移服务负责数据的同步,并在数据同步完成后通知dashboard,dashboard更新etcd的路由关系。proxy通过watch机制,得到新的路由关系,更新内部的路由表,此时app新的请求就会路由到新的集群。

多IDC数据热备

在个推实际业务场景中,推送作为企业级服务,对服务的可用性要求很高,个推有多个机房对外提供服务,每个app归属到一个机房。为了应对机房级故障,我们需要对数据进行多IDC的热备,这样才能在机房发生故障后,将客户的请求路由到非故障机房,从而不影响客户的正常使用。

我们对数据的热备采用集群维度进行,每个集群的数据会备份到另一个机房。proxy收到请求后,根据集群的热备信息,实时将增量数据写入到MQ中,另一个机房的consumer服务不断消费MQ的增量数据,并写入至对应的集群中。dashboard服务负责管控所有IDC的热备任务的状态。

性能

引入一个中间层后,不可避免地会带来一定的性能损失。我们选择 GO 开发的原因,就是希望损失尽可能减小。最终性能结果如下:

由上图可知,QPS降低10%左右,平均延时约等于ES调用和proxy本身平均延时之和。虽然有了10%的性能下降,但是带来了更灵活的运维能力。

当前运行情况

GProxy服务上线之后,顺利完成了ES版本的升级(从1.5升级到6.4),并将原来大集群拆分为多个小集群。整个升级和拆分过程对于业务方无感,并且GProxy提供的无损回滚功能可以让操作更放心(数据的迁移需要十分谨慎)。

有了GProxy的支持,DBA日常对ES运维操作,如参数的优化、集群间的压力平衡,变得更加方便。

结语

个推通过使用Go语言,自主研发了Gproxy,成功解决ElasticSearch大集群存在的问题,为上层业务提供了稳定可靠的数据存储服务。此外,个推也将持续打磨自身技术,在搜索和数据存储领域不断探索,不断拓宽ElasticSearch的应用场景,与开发者一起分享关于如何保证数据存储高可用的最新实践。

相关 [elasticsearch 集群 管理] 推荐:

elasticsearch集群搭建

- - zzm
之前对于CDN的日志处理模型是从 . logstash agent==>>redis==>>logstash index==>>elasticsearch==>>kibana3,对于elasticsearch集群搭建,可以把索引进行分片存储,一个索引可以分成若干个片,分别存储到集群里面,而对于集群里面的负载均衡,副本分配,索引动态均衡(根据节点的增加或者减少)都是elasticsearch自己内部完成的,一有情况就会重新进行分配.

Elasticsearch集群入门

- - 编程语言 - ITeye博客
欢迎来到Elasticsearch的奇妙世界,它是优秀的全文检索和分析引擎. 不管你对Elasticsearch和全文检索有没有经验,都不要紧. 我们希望你可以通过这本书,学习并扩展Elasticsearch的知识. 由于这本书也是为初学者准备的,我们决定先简单介绍一般性的全文检索概念,接着再简要概述Elasticsearch.

ElasticSearch大集群管理维护的难题与个推GProxy解决方案

- - 掘金后端
用户搜索组件和日志管理平台是个推推送服务的重要组成部分. ElasticSearch(简称ES)作为一个开源的分布式搜索引擎,能较好地满足上述要求. 个推在ES的使用上经过了多年迭代,积累了丰富的经验,特别是在数据量不断增大时,如何管理集群、维护集群稳定、优化集群性能,我们进行了许多实践. 本文将从三部分讲述个推ElasticSearch架构的演变过程:大集群的挑战、GProxy如何支持多集群以及当前运行情况.

elasticsearch 1.x集群优化

- - ITeye博客
欢迎发送邮件至 [email protected] 本博文为 Elasticsearch Server2nd的部分第7章部分章节的翻译,版权归原作者. 设置Filter cache. 缓存是提高性能的很重要的手段,es中的filter cache能够把搜索时的filter条件的结果进行缓存,当进行相同的filter搜索时(query不同,filter条件相同),es能够很快的返回结果.

elasticsearch集群监控工具bigdesk

- - zzm
bigdesk是elasticsearch的一个集群监控工具,可以通过它来查看es集群的各种状态,如:cpu、内存使用情况,索引数据、搜索情况,http连接数等. 项目git地址:  https://github.com/lukas-vlcek/bigdesk. 和head一样,它也是个独立的网页程序,使用方式和head一样.

Elasticsearch集群的脑裂问题

- - 互联网 - ITeye博客
所谓脑裂问题(类似于精神分裂),就是同一个集群中的不同节点,对于集群的状态有了不一样的理解. 今天,Elasticsearch集群出现了查询极端缓慢的情况,通过以下命令查看集群状态:. 发现,集群的总体状态是red,本来9个节点的集群,在结果中只显示了4个;但是,将请求发向不同的节点之后,我却发现即使是总体状态是red的,但是可用的节点数量却不一致.

Elasticsearch 索引容量管理实践

- -
作者:gavinyao,腾讯 PCG 后台开发工程师. Elasticsearch 是目前大数据领域最热门的技术栈之一,腾讯云 Elasticsearch Service(ES)是基于开源搜索引擎 Elasticsearch 打造的高可用、可伸缩的云端全托管 Elasticsearch 服务,完善的高可用解决方案,让业务可以放心的把重要数据存储到腾讯云 ES 中.

ElasticSearch-2.0.0集群安装配置与API使用实践

- - 简单之美
ElasticSearch是基于全文搜索引擎库Lucene构建的分布式搜索引擎,我们可以直接使用ElasticSearch实现分布式搜索系统的搭建与使用,都知道,Lucene只是一个搜索框架,它提供了搜索引擎操作的基本API,如果要实现一个能够使用的搜索引擎系统,还需要自己基于Lucene的API去实现,工作量很大,而且还需要很好地掌握Lucene的底层实现原理.

基于docker环境实现Elasticsearch 集群环境

- - 学习日志
最近搭建了es集群的时候,现在需要测试添加一个新的数据节点,项目是使用docker-compose命令来搭建的. 以下基于最新版本 es7.2.0进行. // docker-compose.yaml 集群配置文件. 集群配置了3个master节点,并同时作为数据节点使用,当节点未指定 node.master和node.data的时候,默认值为 true.

Elasticsearch 集群规模和容量规划的底层逻辑

- - IT瘾-dev
问题 1:请问下大家是如何评估集群的规模. 比如数据量达到百万,千万,亿万,分别需要什么级别的集群,这要怎么评估. ps:自己搭建的测试环境很难达到这一级别. 问题 3:我看了很多文章关于 es 集群规划的文章,总感觉乱七八糟的,没有一个统一的规划思路. 如何根据硬件条件和数据量来规划集群,设置多少节点,每个节点规划多少分片和副本.