我们仅利用了列存储文件格式的一半优势吗?

(*最初于2018年发布在LinkedIn上)

列式文件格式已成为大数据系统的主要存储选择,但是当我本周末在Google上搜索相关主题时,我发现大多数文章都在谈论特定列式格式与行格式之间的简单查询基准和存储空间比较。 排序也是列格式的关键特征,但是到目前为止,它的好处和有效实践尚未得到强调或详细解释。 恕我直言,使用没有适当排序的列格式似乎只占基础文件格式优点的一半。 我想分享我对该主题的见解。

互联网和电子商务公司生成的日志/跟踪数据是大数据系统兴起的主要原因,物联网将把这种模式传播到更广泛的行业。 与高度规范化的数据模型相比,无需调用查找过程即可将维度属性规范化为id或代理键,更容易生成此类日志/跟踪数据。 有时,数据模型非常宽泛,因此各种类型的记录器可以生成相同的事件/日志格式(以稀疏方式); 因此记录器可以具有更简单的代码库,并可以产生具有极高QPS / TPS的数据。 不久,此类数据的占用空间已超过S3 / BigTable / HDFS上的数百PB。 然后,列式格式(Dremel / Parquet / ORC / Arrow / CarbonData)得到了拯救。

列格式的优点的前一半是:值按列聚簇,因此压缩效率更高(以减少存储空间),查询引擎可以下推列投影(以减少网络和磁盘的读取I / O, 跳过不需要的列)。 优点的后半部分是:对行顺序进行了适当排序,以将压缩率推至新的水平,并且查询引擎可以下推过滤谓词(以减少读取I / O)并应用矢量化计算。 您可能认为从压缩的CSV / Avro转换为Parquet / ORC应该已经实现了柱状格式90%的好处,但是让我说服您,对数据进行排序的开销是绝对值得的。

我们仅利用了列存储文件格式的一半优势吗?

这是一个案例来说明。 一个典型的网站日志数据集包含:uuid,时间戳,user_id,cookie,user_agent,page_id,refering_site,http_header等。……让我们对具有过滤器针对page_id的流行分析查询进行基准测试:

· 文件系统上的原始Avro(压缩压缩)约为1.4TB; 查询扫描整个1.4TB

· 简单地转换为ORC(zlib压缩)约为0.9TB; 查询扫描〜300GB

· 正确排序的ORC(zlib压缩)约为0.5TB; 查询扫描〜200MB

这类网站日志通常以文本为中心且冗长,因此它们的大小过大(并激起了对大型基础架构进行分析的渴望)。 在以上情况下,user_agent平均包含约200个字符(可容纳40个整数列,),cookie约100个字符,page_id约40个字符。 为了节省大多数存储空间,我们可以按3列的顺序对行进行排序:user_agent,cookie,page_id。

· 将冗长的user_agent的重复值堆叠在一起,将获得最小的编码结果。

· 在同一个user_agent中,行进一步按cookie进行排序,因此user_id和ip_address自然排列,并且大多数重复值对齐。 现在,这三列的压缩率均已优化。

· 下一个排序优先级是page_id,因为:

· page_id(例如电子商务中的product_id)是分析中最常用的过滤条件之一

· 网络访问高度偏向于相对较少的热门page_id

从0.9TB压缩到0.5TB的压缩率提高了44%,而简单的Avro到ORC转换仅实现了(1.4–0.9)/1.4=35%的大小减小。 如果可以将筛选谓词下推到文件读取器,则除了对列进行修剪外,Presto / SparkSQL / Hive还可显着减少从底层文件系统扫描的字节。 这就是为什么使用过滤器WHERE page_id IN(?,?,?,…)的分析查询可以跳过99%的数据块的原因。 这表明直到您将最大的数据集缩小到其1/3大小之前,尚未收获另一半优势,并且您观察到通过PPD(谓词下推)相对于已排序的柱状图提供的令人难以置信的读取时间I / O减少 文件。 PPD是现代计算引擎的重要功能。 您可以在其性能调整文档中找到建议(以使用排序的列式文件格式),但是他们几乎没有详细说明为什么以及如何对数据进行排序。

您喜欢已排序的柱状文件在存储和性能方面的好处,对吗? 但是排序是一项昂贵的操作,尤其是对于大量数据,因此您可能想知道这样做是否负担得起(这会导致数据提取过于繁重或危及SLA)。 以下是一些我认为可以分享的规则:

切勿对大型数据集应用全局排序(以优化列式文件的块/索引布局)。 我们应该始终首先应用分片或范围分区,然后仅对每个存储桶/分区中的行进行排序。

以网络日志为例,我们可以尝试以下策略之一:

· 首先按Cookie将每日流量划分为n个存储桶(只要每个存储单元包含合理数量的记录,n可以为128/256/512 /…),然后按user_agent,cookie,page_id对每个存储桶进行排序

· 首先将每日流量分成两个分区,一个分区用于访客,另一个分区用于登录的用户。 然后按Cookie分行,然后按user_agent,cookie,page_id排序。 这是对第一个选项的扩展,如果很多查询仅关注登录用户的活动,我们会进一步优化文件布局

· 通过虚拟列hour_id = 00/01/02 /../ 23将每日流量分成24个每小时的分区,然后按user_agent,cookie,page_id对每个分区进行排序。 该策略在小时分区之间的数据分布不均匀(与cookie分布相比),但是如果应用了小时过滤,它可以很好地服务于查询

· 将每日流量分成24个每小时的分区,然后按Cookie,ip_address,时间戳对每个分区进行排序。 这种策略不会像第1个第2个选项那样积极地进行压缩,但是通常相同的cookie也会导致相同的user_agent,因此总体压缩效率仍然很高。 此策略不会为基于page_id的谓词提供很多PPD好处,但是此选项非常适合会话化和渠道分析

以电子商务订单表为例,您可以考虑:

· 按order_line_id将整个订单表分成n个存储桶,然后按order_line_id排序。 这是Hive ACID存储表结构。 压缩没有进一步优化,但是它可以基于排序合并操作执行超快速连接和重复数据删除,并可以通过order_line_id快速查找。

· 首先根据虚拟列order_date(从order_timestamp派生)对交易进行分区,然后按order_id或order_line_id将订单分拆为n个存储桶,最后按country_id,product_category_id,product_id和时间戳进行排序。 如果将country_id和product_category_id定义为分区列,则对于记录数量很少的长尾国家/地区,您很容易遇到太多小分区的问题。 一旦在filter子句中使用了country_id和product_category_id,使用排序的列式文件就可以控制文件数量,但仍然提供有效的PPD。

以物联网事件为例:

· 首先按日期,小时和主题进行分区,然后按device_id将事件划分为n个存储桶,并按event_type,subject,device_id和event_time进行排序。 由于subject和event_type是经常在filter和group by子句中使用的字符串,因此查询可以受益于这种排序策略。

· 如果device_id导致偏斜,我们可以保留分区和排序配置,但切换到event_id / uuid作为分片列。

一般来说:

· 如果存在一个字符串列,该字符串列具有长且重复的值,则可以通过排序进一步压缩

· 如果有一列具有中等基数(例如小于500K)并且经常在filter子句中使用(IN,BETWEEN,=,),我们可以通过优先排序此类列来支持PPD优化而不是更好的压缩

· 如果有多个具有低至中基数的列并且所有列都频繁出现在filter子句中,那么我们可以首先对基数最小的列进行排序,然后对基数较大的列进行排序,然后对基数较大的列进行排序。

没有一种万能的排序策略,但是我们总是可以通过节省大量存储空间和/或大大加快流行的查询模式来证明排序的合理性。 无论如何,大多数大型数据集都需要经过压缩或重复数据删除过程,只要我们能够正确分担工作负载,额外的自定义排序开销(每个分片)就不会很大。 最重要的是:如果生成数据文件,然后再读取1000次或更多,则排序将为大型数据集释放出柱状格式的其他好处。

在我们整理分类的柱状文件的注意事项之前,我想提到另一种增压武器-矢量化。 大多数计算模式都会先将列数据块旋转回内存中的行,然后再处理这些行。 如果内存中的数据表示也是列式/矢量化的,许多分析和ML计算操作的速度可以提高10到100倍。 Dremio主要基于端到端的列式+矢量化。 Spark在2. +中添加了矢量化阅读器和优化功能。 如果提供了排序的列输入,则Hive和Presto可以执行矢量化连接和分组。 但是,由于行仍然是数据处理的主要内存格式,因此这些优化尚未得到广泛关注和利用。

· 注意事项1:由于Parquet的普及,Spark / Hive比ORC具有更好的PPD和对Parquet的矢量化读取支持。 您需要首先将嵌套数据结构展平为基本列,然后对ORC数据集进行排序。

Google Big Table + Big Query系统会根据最近的查询模式在后台不断优化排序顺序; Vertica可以将数据块副本放入不同的排序顺序,因此CBO可以选择最佳副本来服务查询。 Netezza和Redshift都对排序表进行了大量优化。 我希望这篇文章可以说服您在大数据系统中充分利用列式文件格式。

(*免责声明:本文中表达的观点仅为作者的观点,并不反映作者的任何政策或立场。)

(本文翻译自Eric Sun的文章《Are We Taking Only Half Of The Advantage Of Columnar File Format?》,参考:https://medium.com/@eric.sun_39815/are-we-taking-only-half-of-the-advantage-of-columnar-file-format-f1bae4927532)


分享到:


相關文章: