从行存储到 RCFile,Facebook 为什么要设计出 RCFile?

从行存储到 RCFile,Facebook 为什么要设计出 RCFile?

过往记忆大数据 过往记忆大数据
2010年,Facebook 的工程师在 ICDC(IEEE International Conference on Data Engineering) 发表了一篇 《RCFile: A Fast and Space-efficient Data Placement Structure in MapReduce-based Warehouse Systems》 的论文,介绍了其为基于 MapReduce 的数据仓库设计的高效存储结构,这就是我们熟知的 RCFile(Record Columnar File)。下面介绍 RCFile 的一些诞生背景和设计。

背景

早在2010年以前,Facebook 的数据仓库每天有超过 20TB 的数据被推入数据仓库(到了 2014 年 Facebook 的仓库存储超过 300PB 的 Hive 数据,而且每天的新增数据在 600TB 左右,那时候已经开始用 ORCFile 了)。按照这么大的增长速度,存储效率是 Facebook 仓库基础设施的重要考虑因素。

为了提高仓库的存储效率,Facebook 在很多方面进行了创新,比如构建冷存储数据中心,在 HDFS 中采用 RAID 等技术来降低复制比率(同时保持高可用性),以及在数据写入 HDFS 之前使用压缩进行数据压缩。但这仍然不能满足他们的需求,所以在这种背景下,RCFile 被开发出来以便尽可能高效地存储 Hive 数仓里面的数据。

大数据处理系统的要求

基于对 Facebook 系统和庞大的用户数据集的分析,Facebook 的工程师总结了 MapReduce 环境下数据存储必须满足以下四个关键需求。

•快速的数据加载。快速加载数据对 Facebook 生产数据仓库至关重要。平均每天有超过 20TB 的数据被推入 Facebook 数据仓库。因此,减少数据加载时间是迫切需要的,因为数据加载期间的网络和磁盘流量会干扰正常的查询执行。
•快速查询处理。为了满足实时网站请求和高并发用户提交的支持决策的查询的高工作负载的要求,查询的响应时间是非常关键的。这要求底层数据存储结构在查询量快速增加时也能够保持高效的查询处理。
•高效利用存储空间。快速增长的用户活动总是要求可伸缩的存储能力和计算能力。有限的磁盘空间实际上需要对数据存储进行良好的管理,以解决有关如何在磁盘中放置数据的问题,以便最大程度地利用空间。
•对经常动态变化的工作负载模式有较强的适应能力。 在实际业务场景中,不同的用户针对不同的目的以多种不同的方式分析数据集。一些数据分析是在固定模式下定期执行的例行任务,而另一些数据分析是从内部平台发出的即席查询。大多数工作负载不遵循任何常规模式,这要求底层系统在有限的存储空间下高度适应数据处理中的各种查询需求,而不是特定于某些查询需求。

为 MapReduce 设计存储格式

为基于 MapReduce 的数据仓库系统设计和实现高效的数据存储格式的一个关键挑战是在 MapReduce 计算环境中来满足上述四个需求。在传统的数据库系统中,有三种数据放置结构得到了广泛的研究,分别是:

•水平行存储结构(horizontal row-store structure )
•垂直列存储结构( vertical column-store structure )
•PAX 混合存储结构(hybrid PAX store structure)
上面的每种存储结构都有其优点,但是仅将这些面向数据库的存储结构移植到基于 MapReduce 的数据仓库系统中并不能完全满足所有四个需求。

简单来说,行存储不能支持快速查询处理,因为当查询仅需要一个具有许多列的宽表中的少数列时,它不能跳过不必要的列读取。其次,列存储经常会导致集群中产生比较较大的网络传输开销,这是因为对于列存储,HDFS 无法保证同一记录中的所有字段都存储在同一群集节点中。尽管将多个列预先分组在一起可以减少开销,但它对响应高度动态的工作负载模式没有很强的适应性。第三,以优化 CPU 缓存性能为目标,在每个磁盘页面内使用列存储的混合PAX结构不能帮助提高用于大数据分析的I/O性能。下面我们来详细介绍这些存储结构的短板。

行存储

行存储结构在传统的数据库系统中占主导地位。使用这种结构,关系记录组织在 N 元存储模型中。一条记录的所有字段按照它们出现的顺序逐个填充,记录被连续地放置在磁盘页面中。下图展示了行存储结构如何在 HDFS 块中存储:

从行存储到 RCFile,Facebook 为什么要设计出 RCFile?
如果想及时了解Spark、Hadoop或者HBase相关的文章,欢迎关注微信公众号:iteblog_hadoop

对于只读数据仓库系统而言,存储以下几个问题:

•第一,如果查询中只需要表中的列的一个子集,那么行存储不能提供快速的查询处理,因为会导致不必要的列读取;
•第二,行存储很难实现高数据压缩率。
行存储对于基于 hadoop 系统的主要优点是数据加载速度快,对动态工作负载的自适应能力强。这是因为行存储保证了同一记录中的所有字段都位于同一集群节点中,因为它们位于同一 HDFS 块中。

列存储

垂直存储方案是基于面向列的存储模型,主要用于读取优化的数据仓库系统中。在垂直存储中,一个关系被垂直划分为若干个子关系,垂直存储的方案基本上有两种:

•一种方案将每一列放在一个子关系中,比如 MonetDB;这种方案称为 column-store。
•另一种方案是将关系中的所有列组织到不同的列组中,并且通常允许多个列组之间的列重叠,比如 C-store 和 Yahoo Zebra 就是这么使用的,这种方案称为 the column-group
下图展示了如何在 HDFS 上如何按列组(column-group)存储的示例。在本例中,列 A 和列 B 存储在同一个列组中,而列 C 和列 D 存储在两个独立的列组中。列式存储可以避免在查询执行期间读取不必要的列,并且可以通过压缩同一数据域中的每一列轻松实现高压缩比。但是,由于元组重构的高开销,它不能在基于 hadoop 的系统中提供快速的查询处理。这种列式存储不能保证同一记录中的所有字段都位于同一集群节点中。例如,本列中一条记录的四个字段存储在可以位于不同节点的三个 HDFS 块中。因此,一次记录重构会导致多个集群节点之间通过网络进行大量的数据传输。正如在最初的 MapReduce 论文中所介绍的,MapReduce 集群中过度的网络传输总是会成为瓶颈来源,应该尽可能避免。

从行存储到 RCFile,Facebook 为什么要设计出 RCFile?
如果想及时了解Spark、Hadoop或者HBase相关的文章,欢迎关注微信公众号:iteblog_hadoop

Hybrid Store: PAX

PAX 使用了一种混合存储结构,旨在提高 CPU 缓存性能。对于具有来自不同列的多个字段的记录,PAX 不是将这些字段放在不同的磁盘页中,而是将它们放在单个磁盘页中,以保存用于记录重构的额外操作。在每个磁盘页中,PAX 使用一个微型页(mini-page)来存储属于每个列的所有字段,并使用一个页头来存储指向微型页的指针。

类似于行存储,PAX 对多种动态查询有很强的适应能力。然而,它并不能满足大型分布式系统对于高存储空间利用率和快速查询处理的需求,原因在于:

•首先,PAX 没有数据压缩的相关工作,这部分与 Cache 优化关系不大,但对于大规模数据处理系统是非常关键的,它提供了列维度数据压缩的可能性;
•其次,PAX 不能提升 I/O 性能,因为它不能改变实际的页内容,该限制使得大规模数据扫描时不易实现快速查询处理;
•最后,PAX 用固定的页作为数据组织的基本单位,按照这个大小,在海量数据处理系统中,PAX将不会有效存储不同大小类型的数据域。

RCFile (Record Columnar File)设计

基于上面的总结,Facebook 为基于 MapReduce 的数据仓库系统(如Hive)设计了一种新的数据放置结构:RCFile。RCFile 应用了来自 PAX 的“首先水平划分数据,然后再垂直划分列”的概念。它结合了行式存储和列式存储的优势。首先,RCFile 保证了同一行中的数据位于同一节点中,因此具有较低的元组重构成本。其次,RCFile 可以利用按列的数据压缩并跳过不必要的列读取。

RCFile 是基于 HDFS 之上设计的,具体如下图所示:

从行存储到 RCFile,Facebook 为什么要设计出 RCFile?
如果想及时了解Spark、Hadoop或者HBase相关的文章,欢迎关注微信公众号:iteblog_hadoop RCFile 的存储设计如下:

•根据 HDFS 的结构,一张表的数据存储在多个 HDFS 块中;
•在每个 HDFS 块中,RCFile 用行组(row group)为基本单元来组织记录。也就是说,存储在 HDFS 块中的所有记录都被划分为一个或多个行组。对于表来说,所有行组具有相同的大小。根据行组的大小和 HDFS 块大小,一个 HDFS 块中有一个或多个行组。
•行组包含三个部分。
•第一部分是放在行组开头的同步标记(sync marker)。同步标记主要用于在 HDFS 块中分离两个连续的行组。
•第二部分是行组的元数据。元数据存储有关此行组中有多少条记录、每列中有多少字节以及每列中每个字段中有多少字节的信息项。
•第三部分是表数据部分,它实际上是一个列存储。在这里,同一列中的所有字段被连续存储在一起。正如上图所示,该部分首先存储列 A 中的所有字段,然后存储列 B 中的所有字段,以此类推。

RCFile 的数据压缩

RCFile 的每个行组中,元数据头部和表格数据段分别进行压缩。

对于元数据头部,RCFile 使用 RLE(Run Length Encoding)算法来压缩数据。由于同一列中所有域的长度值都顺序存储在该部分,RLE 算法能够找到重复值的长序列,尤其对于固定的域长度。

对于数据部分,RCFile 不会对整个数据部分作为整个单元来压缩;相反每个列被独立压缩,RCFile 使用重量级的 Gzip 压缩算法,这是因为可以获得较好的压缩比。此外,由于 Lazy 解压策略,当处理一个行组时,RCFile 不需要解压所有列,可以提高数据的处理效率。

RCFile 对数据部分的所有列使用同样的压缩算法,不过如果使用不同的算法来压缩不同列效果会更好,这也就是 ORCFile 的一项改进。另外,RCFile 还有一些其他缺点,比如区分不同行组时需要扫描同步标记。为了解决这些问题,Facebook 工程师在探索如何更加高效的处理数据,就在同一时刻,HortonWorks 的工程师设计并实现了 ORCFile 文件格式,其就是针对 RCFile 进行了优化,这个我们准备在另外一篇文章进行介绍,敬请关注。

上一篇:从行存储到 RCFile,Facebook 为什么要设计出 RCFile?


下一篇:从行存储到 RCFile,Facebook 为什么要设计出 RCFile?