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

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之间并未做隔离,各功能之间数据查询会互相影响,也是希望解决的难题。

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



http://www.chinasem.cn/article/327433

相关文章

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装