Hadoop 数据压缩和序列化

压缩

文件压缩有两个好处:减少了存储文件所需的空间,并加速数据在网络和磁盘间的传输

常见的压缩格式:


所有的压缩算法都需要在空间和时间上进行权衡,其中splitable表明是否可分,即是否可以搜索数据流的任意位置,并从该位置开始读取数据,可分的数据更适合MapReduce框架处理,如果使用gzip文件作为输入,hadoop通过文件扩展名确定文件不可分,将会使用一个map任务处理所有的数据块,在这种情况下最好在之前的数据处理中,选择合适的数据块大小,将文件切分成块,然后对每个块建立压缩文件

Hadoop 的 codec 算法

通用压缩解压缩算法接口CompressionCodec

public interface CompressionCodec {
  // 对写入的数据进行压缩,输出到out
  CompressionOutputStream createOutputStream(OutputStream out) 
  // 对输入数据流in中的数据进行解压缩
  CompressionInputStream createInputStream(InputStream in) throws IOException;
...
}

public interface SplittableCompressionCodec extends CompressionCodec {
...
  SplitCompressionInputStream createInputStream(InputStream seekableIn,
      Decompressor decompressor, long start, long end, READ_MODE readMode)
      throws IOException;
}

CompressionCodecFactory根据文件名称找到正确的codec

String uri;
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
Path inputPath = new Path(uri);
CompressionCodecFactory factory = new CompressionCodecFactory(conf);
CompressionCodec codec = factory.getCodec(inputPath);

默认情况下会优先使用native类库实现codec,如果查找不到才会使用纯Java实现的算法

hadoop支持的压缩格式有DEFLATE,gzip,bzip2,LZ4,Snappy,此外还可以通过设定io.compression.codecs设定添加额外的编解码器


串行化

Writable

Hadoop 的序列化格式是Writable,对应接口定义了两个方法,用来将数据写入DataOutput二进制流以及从DataInput二进制流读出状态

package org.apache.hadoop.io;

import java.io.DataOutput;
import java.io.DataInput;
import java.io.IOException;
public interface Writable {
  void write(DataOutput out) throws IOException;
  void readFields(DataInput in) throws IOException;
}

WritableComparable

WritableComparable同时实现WritableComparable接口

public interface WritableComparable<T> extends Writable, Comparable<T> 

类型比较对MapReduce来说是至关重要,因为中间有一个基于键值的排序阶段
任何在Hadoop Map-Reduce框架中用作key的类型都应该实现这个接口

RawComparator是一个优化的比较器,可以直接比较对象的字节流,不需要反序列化

public interface RawComparator<T> extends Comparator<T> {
  public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2);
}

WritableComparator

WritableComparator是一个比较器,用来比较WritableComparable类型的数据,实现了RawComparator接口,提供compare(byte[],int,int,byte[],int,int)方法,默认方法是反序列化对象,调用对象本身的compareTo方法

可以通过继承WritableComparator对比较函数compare进行重载优化,同时注册相关类对应的比较器define(Class c, WritableComparator comparator),之后可以直接获取WritableComparator get(Class<? extends WritableComparable> c)

Writable 类

Writable 类的层次结构

Java 基本类型

Java 基本类型都有实现Writable接口的包装类型,char类型除外
通过get和set方法读取存储封装的值
int 和 long 类型有对应的变长格式封装,方便节省空间


Text 类型

使用标准UTF-8编码存储文本

索引:指的是编码后字节序列中的位置
getlength:字节的长度
charAt:Unicode编码的一个码点,类似于String的codePointAt方法
find:返回第一个查找到的位置对应的字节偏移量
Unicode

Unicode 字符集

  • 码点 code point : 一个编码表中的某个字符对应的代码值,书写方式 U+后边跟十六进制数字
  • Unicode :字符集,码点从U+0000到U+10FFFF一共21位,1,112,064个码位,分为17个代码级别,第一个平面称为基本多语言平面(Basic Multilingual Plane, BMP),或称第零平面(Plane 0),其他平面称为辅助平面(Supplementary Planes),基本多语言平面内,从U+D800到U+DFFF之间的码位区块永久保留不映射Unicode字符
  • UTF-8:变长编码规则,把Unicode字符集编码为1到4个字节
  • UTF-16:变长编码规则,把Unicode字符集编码为2个或者4个字节,Java的char类型就是UTF-16编码的一个代码单元
UTF-8
UTF-16

BytesWritable

对字节序列的封装,存储格式为字节数目(4 bytes整数字段),后面跟字节内容本身,内容可以通过set方法改变

NullWritable

不可变单例类型,调用NullWritable.get()获取,序列化长度为0,不从数据流中读取,也不写入数据

ObjectWritable / GenericWritable

ObjectWritable是一个通用的封装,用来处理String,arrays,primitive types,null等等,适合用在一个字段有多种数据类型的情况
在Hadoop RPC中,用来封装和解封装方法参数和返回类型
序列化时,每次要写出封装的类名称,更为高效的方法是使用GenericWritable,声明可能需要的类型,用相应的索引来标识类别,消耗一个字节

Writable 集合类

有6个集合类,分别是ArrayWritable, ArrayPrimitiveWritable, TwoDArrayWritable, MapWritable, SortedMapWritable, EnumSetWritable

  • ArrayWritable / TwoDArrayWritable :对应数组和二维数组的Writabe实例
  • ArrayPrimitiveWritable:对Java 基本数据类型和其数组的包装器类,没有涉及底层复制
  • MapWritable /SortedMapWritable:实现java.util.Map<Writable, Writable> / java.util.SortedMap<WritableComparable, Writable>,K/V的类型信息是串行化格式的一部分,占用一个字节,作为对应类型信息的一个索引,可以存放127种自定义的类型,可以使用NullWritable作为V,存储set集合
  • EnumSetWritable:枚举类型

自定义Writable

可以控制二进制表示形式和排序顺序,更好的提升性能
自定义的实现必须有一个默认构造函数,以便 MapReduce 框架可以实例化,并调用readFields填充字段

自定义比较函数器,直接对字节序列进行比较

 //内嵌一个Comparator内部类
public static class Comparator extends WritableComparator{
    public Comparator() {
      super(外部类.class);
    }
    
    @Override
    public int compare(byte[] b1, int s1, int l1,
                       byte[] b2, int s2, int l2) {
        .....例如
      WritableUtils.decodeVIntSize(b1[s1]) //解析vint / vlong的第一个字节来确定字节长度
    }

    @Override
    public int compare(WritableComparable a, WritableComparable b) {
      .... //两种比较方法应该有相同的语义
    }
}
static {
    WritableComparator.define(外部类.class, new Comparator());
}

序列化框架

序列化框架都必须实现org.apache.hadoop.io.serializer.Serialization接口,通过io.serializations属性指定使用的框架,可以通过代码,也可以通过core-default.xml文件指定

默认属性如下:意味着只有Writable 或 Avro 对象可以在外部序列化/反序列化

<property>
    <name>io.serializations</name>
    <value>
        org.apache.hadoop.io.serializer.WritableSerialization,org.apache.hadoop.io.serializer.avro.AvroSpecificSerialization,org.apache.hadoop.io.serializer.avro.AvroReflectSerialization
    </value>
    <source></source>
</property>

另外还提供了一个Java Serialization序列化形式对应的框架org.apache.hadoop.io.serializer.JavaSerialization

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容