存储格式
行式存储和列式存储
行式存储的优点:查询满足条件的一整行数据时,行式存储的数据查询更快。因为行存储只需要找到其中一个值,其余的值都在相的邻地方,而列式存储则需要去每个聚集的字段找到对应的每列的值。
列式存储的优点:查询满足条件的一整列数据时,列式存储的数据查询更快。因为列存储只需要找到其中一个值,其余的值都在相邻的地方,而行存储则需要去每个聚集的字段找到对应的每个行的值。另一方面,列式存储更便于针对性的设计更好的压缩算法,因为每个字段的数据类型一定是相同的。
常见存储格式
TextFile
TextFile是 Hive 默认的文件格式,属于行式存储。默认数据不做压缩,占用磁盘空间大。 可以结合Gzip、Bzip2进行压缩,Hive 执行查询时会自动解压。使用这种方式压缩的缺点是,Hive不会对数据进行切分, 从而无法对数据进行并行处理。
API:
org.apache.hadoop.mapred.TextInputFormat
org.apache.hive.ql.io.HiveIgnoreKeyTextOutputFormat
建表语句:
create
table
if
not
exists textfile_table(
…
)
row
format
delimited
fields
terminated
by
‘\t’
stored
as textfile;
SequenceFile
SequenceFile是Hadoop API提供的一种二进制文件格式,属于行式存储,具有可分割、可压缩的特点。 SequenceFile格式直接将数据序列化并压缩文件中,所以其文件不能直接查看,可以放在 HDFS 通过hadoop fs -text命令查看。另外,SequenceFile 文件也不支持追加写入。
SequenceFile支持三种压缩选择:
- NONE:不压缩
- RECORD:压缩率低
- BLOCK:压缩率高,一般建议使用BLOCK压缩
API:
org.apache.hadoop.mapred.SequenceFileInputFormat
org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
建表语句:
create
table
if
not
exists seqfile_table(
…
)
row
format
delimited
fields
terminated
by
‘\t’
stored
as sequencefile;
RcFile
RcFile是一种行列存储相结合的文件格式。首先,其将数据按行分块,保证同一个记录在一个块上,避免读一个记录需要读取多个块。然后,块数据列式存储,有利于数据压缩和快速的列存取。
相比TextFile和SequenceFile,RcFile由于列式存储特性,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入、多次读取,因此,相比之下,RcFile更有优势。
API:
org.apache.hadoop.hive.ql.io.RCFileInputFormat
org.apache.hadoop.hive.ql.io.RCFileOutputFormat
建表语句:
create
table
if
not
exists rcfile_table(
…
)
row
format
delimited
fields
terminated
by
‘\t’
stored
as rcfile;
OrcFile
OrcFile 在 Hadoop 0.11 版本后出现,是对RcFile的优化,可以提高hive的读写和处理性能,并提供更高的压缩效率,是目前主流选择之一。
如图所示,每个Orc文件由1个或多个stripe组成,每个stripe250MB大小,这个Stripe实际相当于RowGroup概念,不过大小由4MB至250MB不等,这样能提升顺序读的吞吐率。每个Stripe里有三部分组成,分别是Index Data,Row Data,Stripe Footer:
- Index Data:一个轻量级的index,默认是每隔1W行做一个索引。这里做的索引只是记录某行的各字段在Row Data中的offset。
- Row Data:存的是具体的数据,先取部分行,然后对这些行按列进行存储。对每个列进行了编码,分成多个Stream来存储。
- StripFooter:Stripe Footer:存的是各个stripe的元数据信息。
另外,每个文件有一个File Footer,这里面存的是每个Stripe的行数,每个Column的数据类型信息等;每个文件的尾部是一个PostScript,这里面记录了整个文件的压缩类型以及FileFooter的长度信息等。在读取文件时,会seek到文件尾部读PostScript,从里面解析到File Footer长度,再读FileFooter,从里面解析到各个Stripe信息,再读各个Stripe,即从后往前读。
Parquet
Parquet是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目。
Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
通常情况下,在存储Parquet数据的时候会按照Block大小设置行组的大小,由于一般情况下每一个Mapper任务处理数据的最小单位是一个Block,这样可以把每一个行组由一个Mapper任务处理,增大任务执行并行度。
Parquet格式具备对其他 Hadoop的可移植性,包括Hive, Drill, Impala, Crunch, and Pig。
API:
org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat
org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat
Avro
Avro是一个数据序列化系统,设计用于支持大批量数据交换的应用。它的主要特点有:支持二进制序列化方式,可以便捷,快速地处理大量数据。
Avro对动态语言友好,Avro提供的机制使动态语言可以方便地处理Avro数据。
API:
org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat
org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat
存储格式和数据导入
除了TextFile 格式,其他格式如SequenceFile,OrcFile等格式的表不能直接从本地文件导入数据(Load Data)。数据要先导入到TextFile格式的表中, 然后再用insert select 语句导入到SequenceFile、ORCFile等格式的表中。
压缩算法
数据压缩的优缺点
- 优点:减少空间占用,降低单节点的磁盘IO,提升传输速度。
- 缺点:读取、写入时需要花费额外的资源做压缩和解压缩计算。
压缩算法评价
- 压缩比: 越高越好,以减少空间消耗;
- 压缩时间:越快越好,减少时间消耗;
- 压缩后文件是否可分割:最好支持,这样一个文件可以有多个 Mapper 并行处理,提高速度 ;
常见压缩算法
压缩方式 | 压缩比 | 压缩速度 | 解缩速度 | 是否可分割 |
Gzip | 13.4% | 21 MB/s | 118 MB/s | 否 |
BZip2 | 13.2% | 2.4MB/s | 9.5MB/s | 是 |
LZO | 20.5% | 135 MB/s | 410 MB/s | 是 |
LZ4 | 否 | |||
Snappy | 22.2% | 172 MB/s | 409 MB/s | 否 |
常见编码/解码器
压缩格式 | 对应的编码/解码器 |
Gzip | org.apache.hadoop.io.compress.GzipCodec |
BZip2 | org.apache.hadoop.io.compress.BZip2Codec |
LZO | com.hadoop.compress.lzo.LzopCodec |
Lz4 | org.apache.hadoop.io.compress.Lz4Codec |
Snappy | org.apache.hadoop.io.compress.SnappyCodec |
开启Map输出阶段压缩
开启Map输出阶段压缩,是指在MapReduce的shuffle阶段对mapper产生的中间结果数据压缩,可以减少Job中Map和Reduce任务间数据传输量。这个阶段应优先选择一个低CPU开销的算法。
控制这一功能的激活与禁用的参数为 hive.exec.compress.intermediate,默认为 false。
具体语句:
— 开启hive中间传输数据压缩功能
set hive.exec.compress.intermediate=true;
— 开启mapreduce中map输出压缩功能
set mapreduce.map.output.compress=true;
— 设置mapreduce中map输出数据的压缩方式
set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
— 设置mapreduce中map输出数据的压缩为块压缩
set hive.intermediate.compression.type=BLOCK;
开启Reduce输出阶段压缩
开启Reduce输出阶段压缩,可以减少到各组MapReduce 任务之间的数据传输量,并令最终输出Hive 表的数据也经过压缩。
控制这一功能的激活与禁用的参数为 hive.exec.compress.output,默认为 false。
具体语句:
— 开启hive最终输出数据压缩功能
set hive.exec.compress.output=true;
— 开启mapreduce最终输出数据压缩
set mapreduce.output.fileoutputformat.compress=true;
— 设置mapreduce最终数据输出压缩算法
set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
— 设置mapreduce最终数据输出压缩为块压缩
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
存储和压缩结合
要实现 Hive 表数据压缩,可以在插入数据之前,设置前面提到的压缩相关参数。同时,我们也可以在建表的时候,设置表的相关属性来指定压缩算法和参数,这样插入数据时的时候会自动应用表属性里的压缩配置。
以 Orc 格式为例,Orc 有以下压缩相关的属性:
Key | Default | Notes |
orc.compress | ZLIB | high level compression (one of NONE, ZLIB, SNAPPY) |
orc.compress.size | 262,144 | number of bytes in each compression chunk |
orc.stripe.size | 67,108,864 | number of bytes in each stripe |
orc.row.index.stride | 10,000 | number of rows between index entries (must be >= 1000) |
orc.create.index | true | whether to create row indexes |
orc.bloom.filter.columns | “” | comma separated list of column names for which bloom filter should be created |
orc.bloom.filter.fpp | 0.05 | false positive probability for bloom filter (must >0.0 and <1.0) |
当要创建一个SNAPPY压缩的ORC存储格式时,使用建表语句的 tblproperties 来设置:
CREATE
TABLE orc_snappy(
…
)
ROW
FORMAT
DELIMITED
FIELDS
TERMINATED
BY
‘\t’
STORED
AS orc
tblproperties (“orc.compress”=“SNAPPY”);
或者在建表语句之前,使用 set 命令设置:
set orc.compress=SNAPPY;
CREATE
TABLE orc_snappy(
…
)
ROW
FORMAT
DELIMITED
FIELDS
TERMINATED
BY
‘\t’
STORED
AS orc;
存储格式和压缩格式如何选择
1. 大数据量情况下使用支持分割的压缩格式
若压缩文件不支持分割,那么这个文件只能被一个 Map任务读取。如果该压缩文件很大,那么处理该文件的Map需要花费的时间会远多于读取普通文件的Map时间,这就是常说的Map读取文件的数据倾斜。
要避免这种情况的发生,就需要在数据压缩的时候采用bzip2和Zip等支持文件分割的压缩算法。然而 Orc格式恰恰不支持这些压缩方式,所以这也是大家在遇到大数据量的情况下不选择 Orc的原因。
在数据量较大的情况下,可以使用Parquet存储+ LZO压缩,可以避免由于读取不可分割大文件导致的数据倾斜。
若数据量不大(10 GB以下),ORC存储 + Snappy压缩的效率还是非常高的,可以整体提升Hive的执行速度。
2. 接口表使用TextFile等文本格式
接口表指数据源从外部加载,或者数据需要导出到外部的表。接口表不建议使用 ORC 等格式。
对于加载外部数据的场景:由于文本格式到ORC,需要耗费较高的CPU计算资源,相比于直接落地成文本格式Hive表而言加载性能会低很多;
对于Hive表作为计算结果,导出给外部使用的场景:ORC格式的结果数据,相比于文本格式的结果数据而言其易读性低很多。