HDFS 数据最有效的存储格式

问题描述

我必须在 HDFS 的专用存储服务器上存储大量数据。这是历史数据的某种存档。存储的数据是面向行的,有数十种不同类型的字段。其中一些是字符串,一些是整数,还有一些浮点数、短裤、数组列表和地图。

这个想法是使用 MapReduce 或 Spark 作业不时扫描数据。

目前我将它们存储为 SequenceFiles,其中 NullWritable 作为键,自定义 WritableComparable 类作为值。这个自定义类定义了所有这些字段。

我想实现两个目标 - 一个是优化数据量,因为它变得非常大,我必须每隔几周添加新服务器,而且成本不断增加。另一件事是使添加新字段更容易 - 在当前状态下,如果我想添加一些新字段,我将不得不重写所有旧数据。

我试图通过在这个类中使用 EnumMap 来实现这一点。它给出了相当好的结果,因为它允许轻松添加新字段,并且数据大小减少了 20%(原因是记录中的很多字段通常是空的)。但是我写的代码看起来很糟糕,当我尝试将列表和地图添加到这个 EnumMap 时,它变得更加丑陋。相同类型的数据是可以的,但是尝试组合所有字段是一场噩梦。

所以我想到了一些其他流行的格式。我尝试过 Avro 和 Parquet,但在尝试使用 Enums 之前,数据的大小几乎与带有自定义类的 SequenceFiles 完全相同。所以它解决添加新字段的问题,不需要重写旧数据,但我觉得优化数据大小的潜力更大。

我还要检查的另一件事当然是加载数据所需的时间(这也将告诉我是否可以使用 bzip2 压缩,或者由于性能原因我必须回到 gzip),但在我继续之前,我想知道是否有人会建议其他解决方案或提示

提前感谢所有评论

解决方法

你的大部分方法看起来都不错。我只是决定在这个答案中添加我的一些想法。

存储的数据是面向行的,有几十种不同的类型 的领域。其中一些是字符串,一些是整数,还有 少量 Floats、Shorts、ArrayLists 和 Map。

您在此处提到的所有类型都没有比 datatypes supported by spark 更复杂的类型。所以我不会以任何方式更改数据类型。

实现两个目标 - 一个是优化数据的大小,因为它是 变得非常大,我必须每隔几周添加新服务器 成本在不断增加。

通过添加服务器,您是否也在添加计算?存储应该相对便宜,我想知道您是否正在为您的服务器添加计算,而您实际上并不需要这些计算。您应该只为存储和检索数据付费。考虑像 S3 这样的简单对象存储,它只向您收取存储空间费用并提供免费的访问请求配额 (GET/PUT/POST) - 我相信大约 1000 个请求是免费的,并且每月 1 TB 的存储成本仅为 10 美元左右.

另一件事是更容易添加新字段 - 在当前 声明如果我想添加一些新字段,我将不得不重写 所有旧数据。

如果您有一个用例,您将更频繁地写入文件而不是读取文件,我建议不要将文件存储在 HDFS 上。它更适合一次写入,多次读取类型的应用。也就是说,我建议使用 parquet 开始,因为我认为您将需要一种允许对数据进行切片和切块的文件格式。 Avro 也是一个不错的选择,因为它也支持模式演化。但是,如果您有一个复杂的结构,您需要指定架构并使其更容易使用 Java 对象进行序列化/反序列化,那么最好使用它。

我还要检查的另一件事当然是它的时间 需要加载数据(这也会告诉我是否可以使用 bzip2 压缩或者因为性能我不得不回到gzip)

Bzip2 的压缩率最高,但也是最慢的。因此,如果数据不是真的经常使用/查询,我会推荐它。 Gzip 具有与 Bzip2 相当的压缩率,但速度稍快一些。还可以考虑使用 snappy 压缩,因为它可以在性能和存储之间取得平衡,并且可以支持某些文件类型(parquet 或 avro)的可拆分文件,这对于 map-reduce 作业很有用。