热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

个推无法获取个推id_ElasticSearch大集群管理维护的难题与个推GProxy解决方案

前言用户搜索组件和日志管理平台是个推推送服务的重要组成部分。ElasticSearch(简称ES)作为一个开源的分布式搜索引擎,能较好地满足上述要求。个推在ES的使用

前言

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

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

c5c33e90a102a101704a86b16ded343a.png

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

01

个推ES服务概述

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

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

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

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

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

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

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

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

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

02

大集群的挑战

个推集群演进

46ab0cdb6605e4e7b1b3297b82cade62.png

上图展示的是个推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,暂时缓解一段时间。但随着文档的不断写入,这部分内存占用还是会重新变大。

45e471273194ad02f4f53d6ccae2efc0.png

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

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

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

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

e18eb0fefb7fa86a4378848bebedc6c5.png

此外还有许多隐患。

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

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

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

c3c8534250030658fd3d218f40d9a1fb.png

03

GProxy的解决方案

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

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

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

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

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

0279835d529caa9feb0fbf01a0d9b1b3.png

上图是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来实现服务发现和元数据存储。

4647742d0270d44ab6586414ab2af4c8.png

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机制,监控路由表的变更。

97956c0d9b56f32df28ea4b4de376739.png

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

迁移流程

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

89411fca100a67c92054a15779bb9f9d.png

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

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

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

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

多IDC数据热备

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

2b24dc2b50d61cb6e7f7b1e720be4145.png

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

性能

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

b97c2a0fa39be56ef0c20f77460bf1c4.png

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

当前运行情况

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

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

结语

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

9d7f79b1d9ea53678cefaa9f04454a9b.gif9f92dbce940d7ea2c96bf7a5a906e59e.png7c4dca08d8ad85e9f8ff7de0d2d49b44.png411f6b021e5bdef15e4a3308a1144fc3.gif

bd8f700d21432df9b3e37511644a7146.gif




推荐阅读
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文介绍了Composer依赖管理的重要性及使用方法。对于现代语言而言,包管理器是标配,而Composer作为PHP的包管理器,解决了PEAR的问题,并且使用简单,方便提交自己的包。文章还提到了使用Composer能够避免各种include的问题,避免命名空间冲突,并且能够方便地安装升级扩展包。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了前端人员必须知道的三个问题,即前端都做哪些事、前端都需要哪些技术,以及前端的发展阶段。初级阶段包括HTML、CSS、JavaScript和jQuery的基础知识。进阶阶段涵盖了面向对象编程、响应式设计、Ajax、HTML5等新兴技术。高级阶段包括架构基础、模块化开发、预编译和前沿规范等内容。此外,还介绍了一些后端服务,如Node.js。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 微信官方授权及获取OpenId的方法,服务器通过SpringBoot实现
    主要步骤:前端获取到code(wx.login),传入服务器服务器通过参数AppID和AppSecret访问官方接口,获取到OpenId ... [详细]
author-avatar
php.com
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有