AresDB演示:基于Uber GPU的开源实时分析工具

借助实时分析,我们(Uber员工)可以了解事务状态和工作效率,并根据数据确定如何提高Uber平台上的工作质量。 例如,项目团队监视市场状况并确定我们平台上的潜在问题; 基于机器学习模型的软件可预测乘客对驾驶员的供求情况; 数据处理专家正在改善机器学习模型-从而提高预测质量。



过去,对于实时分析,我们使用了其他公司的数据库解决方案,但没有一个能够满足我们在功能,可伸缩性,效率,成本和运营要求方面的所有标准。


AresDB于2018年11月发布,是一种开源实时分析工具。 它使用非常规电源,图形处理器(GPU),可让您扩大分析规模。 GPU技术是一种有前途的实时分析工具,近年来已取得了显着进步,使其成为实时并行计算和数据处理的理想选择。


在以下各节中,我们将描述AresDB的结构,以及这种有趣的实时分析解决方案如何使我们能够更有效,更合理地统一,简化和改进用于实时分析的Uber数据库解决方案。 我们希望阅读本文后,您可以将AresDB用作自己的项目的一部分,并确保其有用性!


Uber实时分析应用程序


数据分析对于Uber的成功至关重要。 除其他功能外,分析工具还用于解决以下任务:


  • 构建仪表板以监视业务指标。
  • 根据收集的摘要指标进行自动决策 (例如, 确定旅行费用确定欺诈案件 )。
  • 创建随机查询以对业务运营进行诊断,故障排除和故障排除。

我们将这些功能按不同要求分类如下:



仪表盘和决策系统使用实时分析系统,以相对较小但非常重要的数据子集(具有最高的数据相关性)在具有较高QPS和低延迟的情况下创建类似的查询。


需要另一个分析模块


Uber使用实时分析工具解决的最常见问题是计算时间序列总体。 这些计算给出了用户交互的想法,因此我们可以相应地提高服务质量。 基于它们,我们要求在一定的时间段内为某些参数(例如,日期,小时,城市标识符和旅行状态)提供指标,以用于随机过滤(或有时组合)的数据。 多年来,Uber部署了多种旨在以各种方式解决此问题的系统。


以下是一些我们用来解决此类问题的第三方解决方案:


  • Apache Pinot是用Java编写的分布式开源分析数据库,适用于大规模数据分析。 Pinot使用内部lambda体系结构来查询列存储中的数据包数据和实时数据,使用反向位索引进行过滤,以及使用星形树来缓存聚合结果。 但是,它不支持基于密钥的重复数据删除,更新或插入,合并或高级查询功能,例如地理空间过滤。 另外,由于Pinot是基于JVM的数据库,因此在内存使用方面,查询非常昂贵。
  • Uber使用Elasticsearch解决各种流分析任务。 它基于Apache Lucene库构建,该库存储文档,用于全文本关键字搜索和反向索引。 该系统已广泛使用并扩展为支持汇总数据。 倒排索引提供过滤功能,但并未针对基于时间范围的数据存储和过滤进行优化。 记录以JSON文档的形式存储,这增加了提供对存储库和请求的访问的额外成本。 与Pinot一样,Elasticsearch是基于JVM的数据库,因此不支持join功能,并且查询执行占用大量内存。

尽管这些技术有其优势,但它们缺少我们用例所需的某些功能。 我们需要一个统一,简化和优化的解决方案,在搜索过程中,我们的工作方向是非标准的(更确切地说,是在GPU内部)。


使用GPU进行实时分析


为了以高帧速率真实渲染图像,GPU可以同时高速处理大量形状和像素。 尽管在过去几年中增加数据处理单元时钟频率的趋势已经开始下降,但是仅根据摩尔定律 ,芯片中的晶体管数量增加了。 结果,以每秒千兆字节(Gflops / s)为单位测量的GPU计算速度正在迅速提高。 下面的图1显示了多年来NVIDIA GPU和Intel CPU的理论速度趋势(Gflops / s)的比较:



图1.数年来单精度浮点CPU和GPU性能的比较。 图片取自Nvidia的CUDA C编程指南。


在开发实时分析请求机制时,集成GPU的决定是很自然的。 在Uber中,典型的实时分析请求需要在几天之内处理包含数百万甚至数十亿条记录的数据,然后对其进行过滤并在短时间内进行汇总。 该计算任务非常适合通用GPU并行处理模型,因为它们:


  • 它们以很高的速度并行处理数据。
  • 它们提供了更高的计算速度(Gflops / s),这使其非常适合执行可并行化的复杂计算任务(在数据块中)。
  • 与中央处理单元(CPU)相比,它们在计算单元与存储(ALU和全局内存GPU)之间的数据交换中提供了更高的性能(无延迟),这使其成为处理并行内存I / O任务的理想选择。需要大量数据。

我们着眼于基于GPU的分析数据库的使用,从我们的需求出发,评估了几种使用GPU的现有分析解决方案:


  • 基于GPU的分析工具Kinetica于2009年投放市场,最初用于美国陆军和情报机构。 尽管它证明了GPU技术在分析中的巨大潜力,但我们发现由于我们的使用条件,许多关键功能缺失了,包括更改方案,部分插入或更新,数据压缩,列级的磁盘和内存配置以及连接地理空间关系。
  • OmniSci是一个开放源代码SQL查询模块,似乎是一个很有前途的选择,但是在评估该产品时,我们意识到该产品缺少一些可在Uber中使用的重要功能,例如重复数据删除。 尽管OminiSci于2017年推出了其项目的开源代码,但在分析了基于C ++的解决方案后,我们得出的结论是,更改或分支其代码库实际上都不可行。
  • 研究和教育机构经常使用基于GPU的实时分析工具,包括GPUQPCoGaDBGPUDBOcelotOmniDBVirginian 。 但是,鉴于他们的学术目标,这些决策着重于开发算法和测试概念,而不是解决实际问题。 因此,在我们的数量和规模条件下,我们没有考虑它们。

总体而言,这些系统展示了使用GPU技术处理数据的巨大优势和潜力,它们启发了我们创建适合Uber需求的自己的GPU实时分析解决方案。 基于这些概念,我们开发并打开了AresDB的源代码。


AresDB体系结构概述


在较高级别上,AresDB将大多数数据存储在主机内存(连接到CPU的RAM)中,使用CPU处理接收到的数据,并使用磁盘来恢复数据。 在请求期间,AresDB将数据从主机内存传输到GPU内存,以在GPU中进行并行处理。 如下图2所示,AresDB包括内存存储,元数据存储和磁盘:



图2. AresDB的独特体系结构包括内存存储,磁盘和元数据存储。


桌子


与大多数关系数据库管理系统(RDBMS)不同,AresDB没有数据库或架构范围。 所有表都在AresDB的一个群集/实例中属于同一范围,这使用户可以直接访问它们。 用户以事实表和维度表的形式存储数据。


事实表


事实表存储了无尽的时间序列事件流。 用户使用事实表来存储实时发生的事件/事实,并且每个事件都与事件的时间相关联,并且经常在事件的时间查询该表。 作为事实表中存储的信息类型的示例,我们可以命名行程,其中每次行程都是一个事件,并且行程请求的时间通常称为事件时间。 如果一个事件与多个时间戳相关联,则仅将一个时间戳指示为事件的时间,并显示在事实表中。


测量表


测量表存储了设施(包括城市,客户和驾驶员)的当前特征。 例如,用户可以在测量表中存储有关城市的信息,尤其是城市名称,时区和国家/地区。 与不断增长的事实表不同,维度表的大小始终受到限制(例如,对于Uber,城市表受世界上实际城市数的限制)。 测量表不需要特殊的时间列。


资料类型


下表显示了AresDB支持的当前数据类型:



在AresDB中,字符串在进入数据库之前会自动转换为枚举 ,以增加存储和查询效率的便利性。 这允许区分大小写的相等性检查,但不支持高级操作,例如串联,子字符串,掩码和正则表达式匹配。 将来,我们打算添加全线支持选项。


主要功能


AresDB体系结构支持以下功能:


  • 具有压缩功能的基于列的存储,可提高存储效率(用于存储数据的字节内存更少)和查询效率(处理请求时,CPU内存和GPU内存之间的数据交换更少)
  • 使用主键重复数据删除进行实时更新或插入,以提高数据准确性并在几秒钟内更新实时数据
  • GPU请求处理,用于高度并行的GPU数据处理,请求延迟低(从几分之一秒到几秒钟)

列存储


向量


AresDB以列格式存储所有数据。 每列的值存储为列值向量。 每列中值的置信度/不确定性标记存储在单独的零向量中,而每个值的置信度标记则显示为一位。


活动存储


AresDB将未压缩和未排序的列数据(活动向量)存储在活动存储中。 活动存储中的数据记录分为给定卷的(活动)数据包。 接收数据时会创建新数据包,而归档记录后会删除旧数据包。 主键索引用于查找重复数据删除和更新记录。 下面的图3显示了我们如何组织活动记录并使用主键值确定它们的位置:



图3.我们使用主键值来确定包的位置以及包中每个记录的位置。


包中每一列的值都存储为列向量。 每个值向量中值的可靠性/不确定性标记存储为单独的零向量,每个值的可靠性标记以一位表示。 在下面的图4中,我们为city_id列提供了具有五个值的city_id



图4.我们在数据表中存储未压缩列的值(实际值)和零向量(置信标记)。


档案储存


AresDB还通过事实表将完成,排序和压缩的列数据(归档向量)存储在归档存储中。 归档存储中的记录也被分批分发。 与活动软件包不同,存档软件包每天根据协调世界时(UTC)存储记录。 自Unix Epoch以来,归档软件包一直使用天数作为软件包标识符。


记录按照用户定义的列排序顺序以排序形式存储。 如下图5所示,我们首先按city_id列排序,然后按status列排序:



图5.我们按city_id,然后按州对所有行进行排序,然后按组编码对每一列进行压缩。 排序和压缩后,每一列将接收一个记帐向量。


为列设置用户排序顺序的目的如下:


  • 首先通过对包含少量元素的列进行排序来最大化压缩效果。 最大压缩可提高存储效率(需要更少的字节来存储数据)和查询效率(更少的字节在CPU内存和GPU内存之间传输)。
  • 为常见的等效过滤器(例如city_id = 12)提供方便的基于范围的预过滤。 预过滤可最大程度地减少在CPU内存和GPU内存之间传输数据所需的字节数,从而最大程度地提高查询效率。

仅当列以用户指定的排序顺序显示时,才压缩列。 我们不尝试压缩包含大量元素的列,因为这节省了很少的内存。


排序后,使用特定的组编码选项压缩每个合格列的数据。 除了值向量和零向量之外,我们还引入了记帐向量来重新表示相同的值。


实时数据接收,支持更新和插入功能


客户端通过发布Service Pack通过HTTP API接收数据。 Service Pack是一种特殊的有序二进制格式,可在保持对数据的随机访问的同时最大程度地减少空间使用。


AresDB收到Service Pack时,首先将Service Pack写入恢复操作日志。 将Service Pack添加到事件日志的末尾时,AresDB会识别并跳过事实表中的最新条目以用于活动存储。 如果事件时间早于断开事件的存档时间,则该记录被认为是“晚期”。 对于不被视为“后期”的记录,AresDB使用主键索引在要插入它们的活动存储中找到包。 如下图6所示,新记录(以前基于主键值未遇到的记录)被插入空白空间,并且现有记录被直接更新:



图6.接收到数据后,将Service Pack添加到事件日志后,“ late”条目将添加到反向队列,其他条目将添加到活动存储。


存档


接收到数据后,将在活动存储中添加/更新记录,或者将记录添加到反向队列,以等待放置在归档存储中。


关于活动存储的记录,我们会定期启动一个计划的过程,称为归档,以便将新记录(以前从未归档过的记录)附加到归档存储中。 归档过程仅处理活动存储中的记录,事件时间在旧的关闭时间(上次归档过程的关闭时间)和新的关闭时间(基于表布局中的归档延迟参数的新关闭时间)之间的范围内。


记录事件时间用于确定在将归档数据打包到日常数据包中时应合并哪些归档数据包记录。 归档不需要在合并过程中对主键值的索引进行重复数据删除,因为仅会存储新旧关闭时间之间的记录。


下面的图7显示了根据特定记录事件时间的图表。



图7.我们使用事件时间和行程时间将记录定义为新(活动)记录和旧记录(事件时间早于行程事件的归档时间)。


在这种情况下,归档间隔是两个归档过程之间的时间间隔,归档延迟是事件发生后到事件被归档之间的时间段。 这两个参数都在AresDB表架构设置中定义。


回填


如上面的图7所示,事实表的旧记录(其事件时间早于关闭事件的存档时间)被添加到反向队列中,并最终作为回填过程的一部分进行处理。 如果此过程达到阈值级别,则它的触发因素还包括反向队列的时间或大小。 与向活动存储中添加数据的过程相比,回填是异步的,并且在CPU和内存资源方面相对更昂贵。 回填用于以下情况:


  • 处理非常晚的随机数据
  • 从上游数据流中手动捕获历史数据
  • 在最近添加的列中输入历史数据

与存档不同,回填过程是幂等的,需要基于主键的值进行重复数据删除。 填充数据最终将对查询可见。


反向队列将以预定义的大小维护在内存中,并且具有大量回填负载,客户端将阻塞该过程,直到通过启动回填过程清除队列为止。


要求处理


在当前实现中,用户需要使用Uber创建的Ares查询语言 (AQL)在AresDB中执行查询。 AQL是用于时间序列分析查询的有效语言,并且不像其他类似于SQL的语言那样遵循标准的SQL语法,例如“ SELECT FROM WHERE GROUP BY”。 相反,AQL用于结构化字段,并且可以包含在JSON,YAML和Go对象中。 例如,代替/SELECT (*) /FROM /GROUP BY city_id, /WHERE = «» /AND request_at >= 1512000000 ,JSON中的等效AQL变体编写如下:


 { “table”: “trips”, “dimensions”: [ {“sqlExpression”: “city_id”} ], “measures”: [ {“sqlExpression”: “count(*)”} ], ;”> “rowFilters”: [ “status = 'completed'” ], “timeFilter”: { “column”: “request_at”, “from”: “2 days ago” } } 

AQL采用JSON格式,为仪表板和决策系统的开发人员提供了比SQL更方便的程序查询算法,从而使他们可以轻松编写查询并使用代码操作它们,而不必担心SQL注入之类的问题。 它充当Web浏览器,外部和内部服务器直至数据库(AresDB)的典型体系结构的通用查询格式。 另外,AQL提供了一种方便的语法 ,可以按时间进行筛选和批处理,并支持其自己的时区。 此外,该语言还支持许多功能,例如隐式子查询,以防止查询中出现常见错误,并为内部接口开发人员简化了分析和重写查询的过程。


尽管AQL提供了许多好处,但我们深知大多数工程师对SQL更为熟悉。 提供一个用于执行查询的SQL接口是下一步工作之一,我们将以此作为改善与AresDB用户交互的工作的一部分。


AQL查询执行流程图如下图8所示:



图8. AresDB查询流程图使用我们自己的AQL查询语言来快速有效地处理和检索数据。


查询编译


AQL查询被编译到内部查询上下文中。 过滤器,度量和参数中的表达式在抽象语法树(AST)中进行分析,以通过图形处理器(GPU)进行进一步处理。


资料载入


AresDB使用预过滤器便宜地过滤存档数据,然后再将其发送到GPU进行并行处理。 由于已归档的数据是根据配置的列顺序排序的,因此某些过滤器可以使用此排序顺序和二进制搜索方法来确定合适的匹配范围。 特别是,可以将所有最初排序的X列的等效过滤器和排序的X + 1列的可选范围过滤器用作初步过滤器,如下图9所示。



图9. AresDB在将列数据发送到GPU进行处理之前对其进行预过滤。


预过滤后,仅绿色值(符合过滤条件)应发送到GPU进行并行处理。 输入数据被加载到GPU中,并一次处理一个数据包。 这包括活动软件包和归档软件包。


AresDB使用CUDA流进行流水线处理和数据处理。 对于每个请求,两个流交替应用到两个重叠阶段中进行处理。 在下面的图10中,我们提供了一个图形说明该过程。



图10.在AresDB中,两个CUDA线程交替传输和处理数据。


查询执行


为简单起见,AresDB使用Thrust库来实现查询执行过程,该提供了经过微调的并行算法的块,可以在当前工具中快速实现查询。


在Thrust中,使用随机访问迭代器评估输入和输出矢量数据。 每个GPU线程在其工作位置中查找输入迭代器,读取值并执行计算,然后将结果写入输出迭代器中的相应位置。


要评估AresDB表达式,请遵循“每个核心一个运算符”(OOPK)模型。


在下面的图11中,使用在请求编译阶段从维表达式request_at – request_at % 86400生成的AST示例演示了此过程:



图11. AresDB使用OOPK模型评估表达式。


在OOPK模型中,AresDB查询引擎绕过AST树的每个叶节点,并为源节点返回一个迭代器。 如果根节点也是有限的,则根操作直接在输入迭代器上执行。


对于每个非根非结束节点(在此示例中为模运算 ),分配了一个临时工作空间矢量来存储从request_at% 86400表达式获得的中间结果。 使用Thrust,将启动内核函数以在GPU中计算该语句的结果。 结果存储在工作空间迭代器中。


对于根节点,内核功能的运行方式与非根,非有限节点相同。 根据表达式的类型执行各种输出操作,下面将对其进行详细描述:


  • 过滤以减少输入向量元素的数量
  • 将测量输出数据记录在测量向量中,以进行后续数据合并
  • 将参数的输出记录在参数向量中,以进行后续数据合并

在评估表达式之后, 执行排序转换以最终合并数据。 在排序和转换操作中,我们将维向量的值用作排序和转换的关键值,并将参数向量的值用作合并数据的值。 因此,具有相似维度值的行被分组和组合。 下面的图12显示了此排序和转换过程。



图12.评估表达式后,AresDB根据测量向量的关键值(关键值)和参数(值)对数据进行排序和转换。


AresDB还支持以下高级查询功能:



资源管理


作为基于内部内存的数据库,AresDB必须管理以下类型的内存使用:



AresDB启动时,它将使用配置的共享内存预算。 预算分为所有六种类型的内存,并且还应为操作系统和其他进程留出足够的空间。 该预算还包括静态配置的拥塞估计,服务器监视的活动数据存储以及服务器可以根据剩余内存预算决定下载和删除的存档数据。
下面的图13显示了AresDB主机内存模型。



图13. AresDB管理自己的内存使用情况,以使其不超过配置的总流程预算。


AresDB允许用户为事实表设置预加载日和列级优先级,并且仅在预加载日预加载存档的数据。 以前未下载的数据会按需从磁盘加载到内存中。 填充后,AresDB还将从主机内存中删除存档的数据。 AresDB删除的原理基于以下参数:预加载的天数,列的优先级,编译程序包的天和列的大小。


AresDB还管理多个GPU设备,并将设备资源模拟为GPU线程和设备内存,跟踪GPU内存用于处理请求的情况。 AresDB通过设备管理器管理GPU设备,该设备管理器在两个维度(GPU线程和设备内存)中对GPU设备资源进行建模,并在处理请求时跟踪内存使用情况。 编译请求后,AresDB允许用户估计完成请求所需的资源量。 解决请求之前,必须满足设备的内存要求; 如果当前任何设备上的内存不足,则请求应等待。 当前,如果AresDB满足所有资源要求,则可以在同一GPU设备上同时执行一个或多个请求。


在当前的实现中,AresDB不会将输入缓存在设备内存中,以便在多个请求中重复使用。 AresDB旨在支持针对实时实时更新且缓存不正确的数据集的查询。 在AresDB的未来版本中,我们打算实现在GPU内存中缓存数据的功能,这将有助于优化查询性能。


使用示例:Uber概述仪表板


在Uber,我们使用AresDB创建仪表板以获取实时业务信息。 AresDB负责存储具有不断更新的主要事件,并借助低成本的GPU资源在瞬间为它们计算关键指标,因此用户可以交互使用仪表板。 例如,在数据仓库中具有较长有效期的匿名旅行数据会通过多种服务进行更新,包括我们的调度系统,付款和定价系统。 为了有效利用旅行数据,用户可以将数据拆分和分解为不同的维度,以深入了解实时解决方案。


使用AresDB时,Uber仪表板是一种广泛的分析仪表板,公司内部的团队使用该仪表板来生成相关指标和实时响应以改善用户体验。



14. Uber AresDB .


, , :


( )



( )



AresDB


, , AresDB :



, , , , , .


AresDB , Apache Kafka , , Apache Flink Apache Spark .


AresDB


, « » « ». , -. 24 AQL:



:
, , .



, AresDB , , . AresDB , , .



AresDB Uber , . , , AresDB .


:


  • : AresDB, , , .
  • : AresDB 2018 , , AresDB .
  • : , , , .
  • : , (LLVM) GPU.

AresDB Apache. AresDB .


, .


致谢


(Kate Zhang), (Jennifer Anderson), (Nikhil Joshi), (Abhi Khune), (Shengyue Ji), (Chinmay Soman), (Xiang Fu), (David Chen) (Li Ning) , !

Source: https://habr.com/ru/post/zh-CN440072/


All Articles