hadoop深入研究:(十三)——序列化框架,hadoop序列化
转载请写明来源地址:http://blog.csdn.net/lastsweetop/article/details/9376495
所有源码在github上,https://github.com/lastsweetop/styhadoop
框架简介
MapReduce仅仅可以支持Writable做key,value吗?答案是否定的。事实上,一切类型都是支持的,只需满足一个小小的条件:每个类型是以二进制流的形式传输。为此Hadoop提供了一个序列化框架来支持,他们在org.apache.hadoop.io.serializer包中,Writable可以作为MapReduce支持的类型也是因为实现了这个框架,类不多,我们从几个接口说起。Serializer
定义了一组接口,打开流,序列化,关闭流public interface Serializer <T> {
void open(java.io.OutputStream outputStream) throws java.io.IOException;
void serialize(T t) throws java.io.IOException;
void close() throws java.io.IOException;
}Deserializer
定义了一组接口,打开流,反序列化,关闭流public interface Deserializer <T> {
void open(java.io.InputStream inputStream) throws java.io.IOException;
T deserialize(T t) throws java.io.IOException;
void close() throws java.io.IOException;
}Serialization
定义了一组接口,判断是否支持输入的类,根据输入的类给出序列化接口和反序列化接口public interface Serialization <T> {
boolean accept(java.lang.Class<?> aClass);
org.apache.hadoop.io.serializer.Serializer<T> getSerializer(java.lang.Class<T> tClass);
org.apache.hadoop.io.serializer.Deserializer<T> getDeserializer(java.lang.Class<T> tClass);
}WritableSerialization
如果你想自己定义一个类似Writable这样的框架,那么你首先需要的就是实现上面三个接口,那么我们先来看下Writable是如何实现的。public class WritableSerialization extends Configured
implements Serialization<Writable> {
static class WritableDeserializer extends Configured
implements Deserializer<Writable> {
private Class<?> writableClass;
private DataInputStream dataIn;
public WritableDeserializer(Configuration conf, Class<?> c) {
setConf(conf);
this.writableClass = c;
}
public void open(InputStream in) {
if (in instanceof DataInputStream) {
dataIn = (DataInputStream) in;
} else {
dataIn = new DataInputStream(in);
}
}
public Writable deserialize(Writable w) throws IOException {
Writable writable;
if (w == null) {
writable
= (Writable) ReflectionUtils.newInstance(writableClass, getConf());
} else {
writable = w;
}
writable.readFields(dataIn);
return writable;
}
public void close() throws IOException {
dataIn.close();
}
}
static class WritableSerializer implements Serializer<Writable> {
private DataOutputStream dataOut;
public void open(OutputStream out) {
if (out instanceof DataOutputStream) {
dataOut = (DataOutputStream) out;
} else {
dataOut = new DataOutputStream(out);
}
}
public void serialize(Writable w) throws IOException {
w.write(dataOut);
}
public void close() throws IOException {
dataOut.close();
}
}
public boolean accept(Class<?> c) {
return Writable.class.isAssignableFrom(c);
}
public Deserializer<Writable> getDeserializer(Class<Writable> c) {
return new WritableDeserializer(getConf(), c);
}
public Serializer<Writable> getSerializer(Class<Writable> c) {
return new WritableSerializer();
}
}两个内部静态类分别实现Serializer和Deserializer接口,然后getSerializer和getDeserializer分别实例化WritableSerializer和WritableDeserializer,accept方法仅仅是判断输入类是否是Writable的子类。通过io.serializations指定已实现Serialization,各个类之间通过逗号隔开,默认的Serialization有WritableSerialization和Avro中Serialization,这也就是说默认情况下,只有Writable和Avro里的对象可以在MapReduce中使用。那么你可能有疑问了,hadoop是如何知道一个类该交给哪个Serialization呢,答案也在这个包中,请看SerializationFactory
先看他的构造器public SerializationFactory(Configuration conf) {
super(conf);
for (String serializerName : conf.getStrings("io.serializations",
new String[]{"org.apache.hadoop.io.serializer.WritableSerialization"})) {
add(conf, serializerName);
}
}可知他是从io.serializations属性指定的实现了Serialization的类,然后再看他是如何知道选哪个Serialization的 public <T> Serialization<T> getSerialization(Class<T> c) {
for (Serialization serialization : serializations) {
if (serialization.accept(c)) {
return (Serialization<T>) serialization;
}
}
return null;
}好吧,就是这么简单,判断一下是否是对应的子类而已。这个包里还实现了JavaSerialization,其实就是Java对象的序列化,很多人觉得,这个好简单的,我只要实现java中的序列化接口就可以了,不用那么费事搞什么Writable和Avro,但是,千万别这么想,非常不推荐使用java对象的序列化,并且详尽的解释为什么不推荐:为什么不使用java序列化
1.java序列化不够灵活,为了更好的控制序列化的整个流程所以使用Writable
2.java序列化不符合序列化的标准,没有做一定的压缩,java序列化首先写类名,然后再是整个类的数据,而且成员对象在序列化中只存引用,成员对象的可以出现的位置很随机,既可以在序列化的对象前,也可以在其后面,这样就对随机访问造成影响,一旦出错,整个后面的序列化就会全部错误,但是
Writable完美的弥补了这一点,因为Writable中每一条纪录间是相互独立的
3.Java序列化每次序列化都要重新创建对象,内存消耗大,而Writable是可以重用的。
序列化IDL
为了和其他语言交互,必须定义序列化的IDL,原先定义的IDL在org.apache.hadoop.record包里,但是后来一直没用起来就淘汰掉了,现在比较常用的就是Avro,后面我们会重点着墨讲解。Apache的Thrift和Google的Protocol Buffer也是比较流行的序列化框架,但是在Hadoop里使用是有限的,只用于RPC和数据交互,不过有一个开源项目elephant-bird可以把他们使用在MapReduce上。如果我的文章对您有帮助,请用支付宝打赏:
本站文章为和通数据库网友分享或者投稿,欢迎任何形式的转载,但请务必注明出处.
同时文章内容如有侵犯了您的权益,请联系QQ:970679559,我们会在尽快处理。