​爱奇艺|海量数据实时分析服务技术架构演进

2023-11-02 02:20

本文主要是介绍​爱奇艺|海量数据实时分析服务技术架构演进,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.现状与挑战

爱奇艺目前使用到的大数据相关技术有Druid、Impala、Kudu、Kylin、Presto、ElasticSearch等,并且随着各技术框架的版本升级而升级。 比如:
  • Druid是一个分布式的支持实时分析的数据存储系统,数据与时间强相关,已由0.10.0版本升级到0.14.2版本;

  • Impala是Cloudera受谷歌Dremel启发开发的实时交互SQL大数据查询工具;

  • Kudu是Cloudera开源的存储引擎,可以同时提供低延迟的随机读写和高效的数据分析能力;

  • Kylin是Apache开源的一个分布式引擎, 提供了在Hadoop之上的SQL查询接口及OLAP能力,支持超大规模数据;

  • Presto是一个分布式的SQL查询引擎,其设计专门用于进行高速、实时的数据分析;

  • ElasticSearch是一个高可靠、可扩展、分布式的全文搜索引擎。

不同的业务场景需要不同的大数据技术架构,对于爱奇艺号而言,因单日数据量达到亿级且分固定时间选择和自由时间选择(至少查询近2年数据)查询数据的业务特点,因此采用的是Druid和ElasticSearch的组合技术架构,其中自由时间选择查询Druid,而固定时间选择查询ElasticSearch。同时,为了保证数据的高可用,Druid和ElasticSearch都有主备2份数据。

然而,在使用Druid和ElasticSearch的过程中也遇到了一些 挑战 ,比如:

Druid本身对数据写入和查询只提供了基于JSON的API接口,学习接口的使用方法,了解各种字段含义,学习成本很高;另外,数据的安全性,在早期的Druid版本中支持较弱;再有,高qps长时间跨度的聚合查询也是一个很大的挑战。

对于ElasticSearch,因不适用于大数据量的聚合计算,要尽量避免此种应用场景,且ElasticSearch提供的RESTful API的查询接口学习成本也相对较高。另外,因为Druid集群是服务于公司全部业务的,如何做业务隔离也是一个严峻的挑战。

2.技术架构演进

在最初的爱奇艺号数据服务中,主要采用的是Kylin,架构如下图所示:

640?wx_fmt=png

服务分集群部署,每个集群部署多台机器,固定时间选择和自由时间选择查询的都是Kylin,并对数据进行缓存。 因爱奇艺号作品数据查询的是视频明细数据的特点,随着业务的发展,爱奇艺号用户以及上传视频量快速增长,导致Kylin Cube的构建时长和查询时长明显增加,甚至会出现查询超时的情况。 另外,Kylin构建Cube过程很是不稳定,经常会出现构建失败或超时的情况,需要耗费大量的人力成本去处理上述异常情况。

基于此,我们进行了新的技术选型,对Impala+Kudu、ElasticSearch、Druid等技术架构进行了对比。最后,因Druid具有超大数据规模、毫秒级查询时延、高并发查询、高稳定性等的特点,故爱奇艺号选择Druid平台作为底层架构。而对于固定时间选择,因其时间固定且视频量级为亿级,故采用ElasticSearch存储和查询,重新选型后的架构如下图所示。

640?wx_fmt=png

爱奇艺号的作品数据查询分为两个部分: 固定时间范围查询和自由时间范围查询,我们对固定时间范围查询结果进行预计算且结果存入ElasticSearch,这样免去了大数据集上的实时聚合和排序,查询性能得到了很大提升; 自由时间范围选择查询Druid,因为是分天查询视频数据,所以Druid的Segment粒度是天,但若用户选择的数据查询时间跨度比较大,那么Druid扫描的Segment数量就会增加,加载进内存的数据会增加,聚合数据速度会变慢,针对此种场景,爱奇艺号导入了按月分Segment数据的DataSource,即把每个视频1个自然月的数据汇总到一个Segment,这样减少了扫描的Segment数量,加载进内存的数据减少,数据聚合速度会变快。 经过测试,当用户选择的时间范围跨度大于6个月时,将查询时间范围拆分成自然月与自然日的两个时间范围并行查询,查询时间会明显缩短。

经过上述优化,一个普通的爱奇艺号用户查询数据时长由2s+缩减至150ms+,性能提升十分明显,用户反馈良好,固定时间选择具体性能对比如下图所示:

640?wx_fmt=png

由上图可以看出,优化后昨日/近7天/近90天的数据查询时间明显缩短,且数据查询时长并不随着时间范围的扩大而明显增加,固定时间维度查询优化明显。 自由时间选择的查询性能对比如下图:

640?wx_fmt=png

由上图可以看出,优化后自由时间选择的查询时长明显优于优化前,查询时长是数量级级别的差异。但当用户的视频量比较大时,Druid的查询性能明显下降,于是我们通过扩容集群机器等方式进一步解决用户视频量大而导致查询变慢的问题。

另外,为了预防Druid集群故障,我们采用主备Druid集群的方式存储了2份同样的数据,当主Druid集群出现故障不可用时,采用Hystrix的服务降级,改成查询备份的Druid集群数据,从而保证服务高可用。 因为固定时间维度查询预计算好的ElasticSearch结果,缓解了Druid查询压力,且对查询过的数据进行Redis缓存,进一步降低ElasticSearch和Druid的查询压力,从而保证服务的稳定性,接口成功率提升至99.9%。

3.选择Druid的原因

Druid是一个用于大数据实时查询和分析的高容错、高性能开源分布式系统,旨在快速处理和查询,Druid的架构如下图所示:

640?wx_fmt=png

Druid主要包含以下5类 节点

  • MiddleManager节点:摄入数据以及生成Segment数据文件

  • Historical节点:加载已生成好的数据文件,以供数据查询

  • Coordinator节点:负责历史节点的数据负载均衡,以及通过规则管理数据的生命周期

  • Overload节点:负责数据摄入的负载均衡

  • Broker节点:对外提供数据查询服务,并同时从MiddleManager节点和Historical节点查询数据,合并后返回给调用方 

同时,集群还包括以下三类外部依赖

  • Metadata:存储Druid集群的元数据信息,比如:Segment的相关信息,一般是MySQL。

  • Zookeeper:为Druid集群提供一致性协调服务。

  • Deep Storage:存放生成的Segment数据文件,并共Historical节点下载,一般是HDFS。

Druid为何能支持如何快速的查询呢?下面为你详细介绍。

在介绍Druid快速查询原理之前,首先介绍一下Druid的数据查询过程。

查询节点接收外部Client的查询请求,并根据查询中指定的interval找出相关的Segment,然后找出包含这些Segment的实时节点和历史节点,再将请求分发给相应的实时节点和历史节点,最后将来自实时节点和历史节点的查询结果合并后返回给调用方。其中,查询节点通过Zookeeper来发现历史节点和实时节点的存活状态。

下图展示了在系统架构中查询请求数据如何流动,以及哪些节点涉入其中。

640?wx_fmt=png

查询具体过程 如下:

  1. 查询请求首先进入查询节点,查询节点将与已知存在的Segment进行匹配查询;

  2. 查询节点选择一组可以提供所需要的Segment的历史节点和实时节点,将查询请求分发到这些机器上;

  3. 历史节点和实时节点都会进行查询处理,然后返回结果;

  4. 查询节点将历史节点和实时节点返回的结果合并,返回给查询请求方。

Druid快速查询 主要有以下3个原因:

  • 内存式查询

  • 缓存的使用

  • Segment特殊存储格式:列式存储、Bitmap索引、RoaringBitmap Compression

首先,Druid是一个内存式的数据库,设计初衷就是数据的查询落到内存中,如果内存足够大,可以保证所有的数据都加载到内存中;其次,如果Broker节点上已经缓存本次查询的结果(即之前查询过与本次查询完全相同的查询),那么Broker节点直接返回数据给客户端,而无需再查询各历史节点,进一步提高了查询速度;再次,基于Druid基本存储单位Segment的特殊存储格式,列式存储保证了,每次查询只查询其需要的列,而不必查询出一行中的所有数据列,Bitmap索引的使用,保证了其快速查询。

下面重点介绍一下其中Bitmap索引: 

我们考虑如下场景,一场举世瞩目的篮球名人慈善赛在洛杉矶举行,所得善款全部用于公益事业,参加篮球赛的有现勇士球星Curry和Durant,著名歌手Beyonce、Biber,还有另外一名Curry女士参加等等。 其中每人得分及相应捐款如下:

640?wx_fmt=png

如果想查询出篮球运动员Curry的得分情况和捐款情况,如何快速查询出来呢?

首先,为每个字段中的每个值建立一个Bitmap索引,上述中共有name/gender/profession/score/donation 5个非时间字段,其中name/gender/profession属于维度列,score/donation属于度量列。对于name这个字段,因为其有4个值,Curry、Durant、Beyonce、Biber4个值,因此有4个Bitmap,每个Bitmap 0表示无,1表示有,Bitmap大小由数据条数决定,即有多少条数据,这个Bitmap的size就是多大。

Curry对应的Bitmap如下:

1

0

0

0

1

Profession中basketball player的Bitmap如下:

1

1

0

0

0

要查询勇士球星Curry的记录的话,就直接用上述两个Bitmap做"与"运算即可,得出:

1

0

0

0

0

这样的话,即可得出第一行即为其查询结果。
另外,对于同一个字段的各个值,其中只有与记录条数相等的1的个数,其余全是0(比如: 对于name字段,其有4个值,5条记录,那么对于这4个值得4个Bitmap中,仅有5个值为1),可以使用压缩算法对其进行压缩,Druid使用的是Roaring Bitmap Compression,详情请见: https://roaringbitmap.org/ 。

4.展望

Druid在0.10版本之后开始支持SQL,且随着版本的升级支持的SQL函数也越来越多,但因为Druid SQL本质上是一个语言翻译层,受限于Druid本身的查询处理能力,支持的SQL功能有限。 Druid目前并没有支持JOIN查询,所有的聚合查询都被限制在单个DataSource进行,但在实际的使用过程中,往往需要不同DataSource进行关联查询才能得到想要结果,这也是目前Druid开发团队的难题。

现在爱奇艺大部分DataSource的Segment的粒度是天或小时级的,当需要查询的时间跨度比较大时,会导致查询变慢,占用大量Historical节点资源,可以创建一个Batch任务,把几天前(或几周前)的数据按照天或月粒度Roll up重新构建Index,当查询时间跨度较大时,性能会有明显提升。

此外,因为目前爱奇艺号不同功能使用的是同一个Druid集群,只是在DataSource间做数据隔离,但是数据查询Broker之间并未做隔离,各功能之间数据查询会互相影响,也是希望解决的难题。

这篇关于​爱奇艺|海量数据实时分析服务技术架构演进的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/rlnLo2pNEfx9c/article/details/101042840
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/327433

相关文章

RabbitMQ消息总线方式刷新配置服务全过程

《RabbitMQ消息总线方式刷新配置服务全过程》SpringCloudBus通过消息总线与MQ实现微服务配置统一刷新,结合GitWebhooks自动触发更新,避免手动重启,提升效率与可靠性,适用于配... 目录前言介绍环境准备代码示例测试验证总结前言介绍在微服务架构中,为了更方便的向微服务实例广播消息,

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

解决1093 - You can‘t specify target table报错问题及原因分析

《解决1093-Youcan‘tspecifytargettable报错问题及原因分析》MySQL1093错误因UPDATE/DELETE语句的FROM子句直接引用目标表或嵌套子查询导致,... 目录报js错原因分析具体原因解决办法方法一:使用临时表方法二:使用JOIN方法三:使用EXISTS示例总结报错原

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

Python使用vllm处理多模态数据的预处理技巧

《Python使用vllm处理多模态数据的预处理技巧》本文深入探讨了在Python环境下使用vLLM处理多模态数据的预处理技巧,我们将从基础概念出发,详细讲解文本、图像、音频等多模态数据的预处理方法,... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

关于DNS域名解析服务

《关于DNS域名解析服务》:本文主要介绍关于DNS域名解析服务,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录DNS系统的作用及类型DNS使用的协议及端口号DNS系统的分布式数据结构DNS的分布式互联网解析库域名体系结构两种查询方式DNS服务器类型统计构建DNS域

Knife4j+Axios+Redis前后端分离架构下的 API 管理与会话方案(最新推荐)

《Knife4j+Axios+Redis前后端分离架构下的API管理与会话方案(最新推荐)》本文主要介绍了Swagger与Knife4j的配置要点、前后端对接方法以及分布式Session实现原理,... 目录一、Swagger 与 Knife4j 的深度理解及配置要点Knife4j 配置关键要点1.Spri