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

PrestoORC及其性能优化

简介

ORC的全称是(Optimized Row Columnar),其是为了加速Hive查询以及节省Hadoop磁盘空间而生的,其使用列式存储,支持多种文件压缩方式。由于其被广泛应用在Hadoop系统中,Presto 0.77版本在Hive Connector里实现了ORC Reader。

ORC文件结构Presto ORC及其性能优化

上图(图1)来自网络,有很多文章通过这张图片介绍了ORC文件结构,我这里就不多啰嗦了,我们直接通过数据来看文件格式吧。

创建表:Presto ORC及其性能优化

插入数据:

 
  1. insert into orc(id,name) values(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'),(7,null);

注:我们想只生成一个文件,所以一次插入了7条数据,否则会生成多个文件,不利于我们后续分析。

Dump数据:

使用Hive自带的ORC DUMP工具,命令:

 
  1. ./bin/hive --orcfiledump hdfs://localhost:9000/user/hive/warehouse/orc/000000_0

数据格式

Presto ORC及其性能优化

上图由回车划分了5个模块,第五个模块表示该ORC文件数据大小,我们不需要关心。

  • 模块1 对应图1里面的PostScript,包含压缩类型及表结构信息

  • 模块2 Stripe Statistics对应图1里面的Stripe Footer,Stripe粒度的索引,可以看到其包含3列,Column 1 对应 id字段,包含其最大值和最小值以及包含其sum总和,其中也有个 hasNull标记,用于标记是否含有NULL,此字段可用于SQL里带有 isnull 的优化,Column 2对应 name字段,与Column 1相似,但是sum表示非NULL值的行数。注意此处只含有1个Stripe,默认为10000,参数hive.exec.orc.default.row.index.stride可控制其大小,简单测试了下,发现此值最小为1000,否则生成MR出错,具体需要代码里再确认下。Column 0只统计其count值,可以忽略。

  • 模块3 对应图1里面的File Footer,与Stripe Footer相似,但是是文件级别的索引。

  • 模块4 stripe详细信息,就是真实列数据块,其中又分为Index data(记录每列的索引信息),Raw Data(记录原始数据),Index data可以根据自身业务特点做些性能调优,比如实现布隆过滤器索引(Hive 1.2实现)。Raw Data是通过row group保存的,其实可以简单的认为就是默认按照10000将原始数据划分更小的块,每一个row group由多个stream保存数据和索引信息。每一个stream的数据会根据该列的类型使用特定的压缩算法保存。在ORC中存在如下几种stream类型:

  • PRESENT:每一个成员值在这个stream中保持一位(bit)用于标识该值是否为NULL

  • DATA:当前stripe的成员值,真实数据

  • LENGTH:每一个成员的长度,string类型特有,否则你不知道每个string的长度

  • DICTIONARY_DATA:对string类型数据编码之后字典的内容

  • SECONDARY:存储Decimal、timestamp类型的小数或者纳秒数等

通过模块4,我们可以看到 id含列有DATA Stream,而 name含有PRESENT、DATA、LENGTH Stream,因为存在空值,所以多了个PRESENT Stream。

Presto ORC及优化

Presto在实现ORC时,Hive-based ORC reader维护的数据是行式的,Presto想使用官方提供的客户端时还需要将行数据转换为列数据,且当时不支持Predicate pushdown,所以索性Presto自己实现ORC Reader,不过Hive 0.13也实现了VectorizedOrcRecordReader提供列格式。

Predicate pushdown

由ORC文件格式分析,ORC在每个文件中提供三级索引:

  • 文件级别,整个文件级别的统计信息

  • stripe级别,每个stripe每列中的值的统计信息

  • 行级别 (行组),stripe中每组10000行(默认值)的每列值的统计信息

假如查询过滤条件为WHERE id = 1,首先从文件的统计信息(一级索引)中看看id字段的min/max值,如果1不包含在内,那么跳过该文件;如果在这个文件中,那么继续查看二级索引,每个stripe中id字段的min/max值,如果1不包含在内,那么跳过此stripe;如果在该stripe中,则继续匹配row group中的min/max值(三级索引),如果1不包含在内,那么跳过该row group。如果1包含在内min和max范围内,则利用布隆过滤器再次判断是否一定不在内,不在内则继续跳过该行组。其原理就是通过三级索引,将查询范围缩小到10000行的集合,而原始数据是列式存储,更加适合CPU pipeline的编码方式,有效利用这种局部性,缓存可以达到极高的命中率,所以ORC有非常高效的性能。

Lazy reads

以SQL为例, SELECT a,b FROM...WHERE a=...,如果a不匹配,那么将不会读取b的列。

Bulk reads

Presto老版本ORC Reader代码可以简化为以下逻辑:

 
  1. if (dataStream == null) {

  2. presentStream.skip(nextBatchSize);

  3. return RunLengthEncodedBlock.create(type, null, nextBatchSize);

  4. }

  5.  

  6. BlockBuilder builder = type.createBlockBuilder(null, nextBatchSize);

  7. if (presentStream == null) {

  8. for (int i = 0; i

  9. type.writeLong(builder, dataStream.next());

  10. }

  11. }

  12. else {

  13. for (int i = 0; i

  14. if (presentStream.nextBit()) {

  15. type.writeLong(builder, dataStream.next());

  16. }

  17. else {

  18. builder.appendNull();

  19. }

  20. }

  21. }

  22. return builder.build();

比如float及double的datatStream.next()实现为:

 
  1. public float next()

  2. throws IOException

  3. {

  4. input.readFully(buffer, 0, SIZE_OF_FLOAT);

  5. return slice.getFloat(0);

  6. }

一次只读取一个值,将其改为按照Bulk loading(比如8*SIZEOFFLOAT),读取性能有明显提升。而对于Boolean reader,之前一次处理 1 bit数据(但是读取按照Byte),优化点是将其改为一次处理 8 bit(1 Byte)。

Improve null reading

从上面的代码可以看到,当有PRESENT Stream时(就是存在null值时),还要每次处理PRESENT Stream,读取DATA Stream及 PRESENT Stream,CPU Cache利用率很低,所以上面代码改为了下面形式:

 
  1. // bulk read and count null values

  2. boolean[] isNull = new boolean[nextBatchSize];

  3. int nullCount = presentStream.getUnsetBits(nextBatchSize, isNull);

  4.  

  5. // bulk read non-values into a temporary array

  6. dataStream.next(tempBuffer, nextBatchSize - nullCount);

  7.  

  8. // copy values into result

  9. long[] result = new long[isNull.length];

  10. int position = 0;

  11. for (int i = 0; i

  12. result[i] = tempBuffer[position];

  13. if (!isNull[i]) {

  14. position++;

  15. }

  16. }

先将数据读取临时文件里,然后依次处理。

Avoid dynamic dispatch in loops

 
  1. for (int i = 0; i

  2. type.writeLong(builder, dataStream.next());

  3. }

很多Stream Reader只包含一种type,但是LongStreamReader会包含BIGINT、INTEGER、SMALLINT、TINYINT 及 DATE Types。这会让JVM的一些优化失效,比如inline,改动为:

 
  1. if (type instanceof BigintType) {

  2. BlockBuilder builder = type.createBlockBuilder(null, nextBatchSize);

  3. for (int i = 0; i

  4. type.writeLong(builder, dataStream.next());

  5. }

  6. return builder.build();

  7. }

  8. if (type instanceof IntegerType) {

  9. BlockBuilder builder = type.createBlockBuilder(null, nextBatchSize);

  10. for (int i = 0; i

  11. type.writeLong(builder, dataStream.next());

  12. }

  13. return builder.build();

  14. }

  15.  

  16. ...

因为早期Hive ORC Reader的一些特性,导致Presto自己实现了ORC Reader,但是现在来看,直接调用社区的ORC Reader效果会更好,因为Presto基本上每2、3个小版本就会修复ORC Bug或者做些简单的性能提升,但是代码里很多都是来源于社区ORC的代码,Presto社区整体进展缓慢,直接调用社区ORC接口,省下了优化和修复Bug的时间,剩下的时间做些Presto引擎更核心的事情应该才是正确的做法。

参考链接

  • https://orc.apache.org/specification/ORCv1/

  • https://prestosql.io/blog/2019/04/23/even-faster-orc.html


推荐阅读
  • 对于开源的东东,尤其是刚出来不久,我认为最好的学习方式就是能够看源代码和doc,測试它的样例为了方便查看源代码,关联导入源代 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • Windows7企业版怎样存储安全新功能详解
    本文介绍了电脑公司发布的GHOST WIN7 SP1 X64 通用特别版 V2019.12,软件大小为5.71 GB,支持简体中文,属于国产软件,免费使用。文章还提到了用户评分和软件分类为Win7系统,运行环境为Windows。同时,文章还介绍了平台检测结果,无插件,通过了360、腾讯、金山和瑞星的检测。此外,文章还提到了本地下载文件大小为5.71 GB,需要先下载高速下载器才能进行高速下载。最后,文章详细解释了Windows7企业版的存储安全新功能。 ... [详细]
  • 本文介绍了如何使用MATLAB调用摄像头进行人脸检测和识别。首先需要安装扩展工具,并下载安装OS Generic Video Interface。然后使用MATLAB的机器视觉工具箱中的VJ算法进行人脸检测,可以直接调用CascadeObjectDetector函数进行检测。同时还介绍了如何调用摄像头进行人脸识别,并对每一帧图像进行识别。最后,给出了一些相关的参考资料和实例。 ... [详细]
  • Maven构建Hadoop,
    Maven构建Hadoop工程阅读目录序Maven安装构建示例下载系列索引 序  上一篇,我们编写了第一个MapReduce,并且成功的运行了Job,Hadoop1.x是通过ant ... [详细]
  • 什么是大数据lambda架构
    一、什么是Lambda架构Lambda架构由Storm的作者[NathanMarz]提出,根据维基百科的定义,Lambda架构的设计是为了在处理大规模数 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 本文整理了Java中org.apache.hadoop.hbase.client.Increment.getDurability()方法的一些代码示例,展示了 ... [详细]
  • Flink使用java实现读取csv文件简单实例首先我们来看官方文档中给出的几种方法:首先我们来看官方文档中给出的几种方法:第一种:Da ... [详细]
  • 【转】腾讯分析系统架构解析
    TA(TencentAnalytics,腾讯分析)是一款面向第三方站长的免费网站分析系统,在数据稳定性、及时性方面广受站长好评,其秒级的实时数据更新频率也获得业界的认可。本文将从实 ... [详细]
author-avatar
blovejin
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有