java 序列化框架_java – 处理序列化框架的不兼容的版本更改

在Hadoop集群中,由于Kryo序列化框架的版本升级导致的不兼容问题,使得直接更换版本将无法读取旧数据。文中探讨了三种可能的解决方法:1) 使用Maven Shade Plugin重命名包和创建不同版本;2) 通过多个类加载器实例化不同版本的Kryo;3) 中间序列化,如JSON转换。每个方法都有其挑战,如重命名的复杂性、类加载器的问题和额外的存储消耗。
摘要由CSDN通过智能技术生成

问题描述

我们有一个Hadoop集群,我们存储使用Kryo(序列化框架)将数据序列化为字节的数据.我们以前做过的Kryo版本已经从官方版本2.21中分离出来,将我们自己的补丁应用到使用Kryo所遇到的问题上.目前的Kryo版本2.22也解决了这些问题,但是使用了不同的解决方案.因此,我们不能仅仅更改我们使用的Kryo版本,因为这将意味着我们将无法再读取已经存储在Hadoop集群中的数据.为了解决这个问题,我们要运行一个Hadoop作业

>读取存储的数据

>反序列化旧版Kryo存储的数据

>使用新版本的Kryo序列化恢复的对象

>将新的序列化表示写回我们的数据存储

问题是在一个Java程序中使用同一个类的两个不同版本(更确切地说,在Hadoop作业的映射器类中)并不是微不足道的.

简单的问题

在一个Hadoop作业中,如何使用两个不同版本的同一序列化框架反序列化序列化对象?

相关事实概述

>我们将数据存储在Hadoop CDH4集群中,序列化为Kryo版本2.21.2-ourpatchbranch

>我们希望将数据序列化为Kryo版本2.22,这与我们的版本不兼容

>我们用Apache Maven构建我们的Hadoop工作JAR

可能(和不可能)的方法

(1)重命名软件包

我们想到的第一个方法是使用relocation functionality of the Maven Shade plugin重命名我们自己的Kryo分支中的软件包,并使用不同的工件ID进行发布,以便我们可以依赖于我们的转换作业项目中的两个工件.然后,我们将实例化旧版本和新版本的一个Kryo对象,并使用旧版本进行反序列化,并将新的对象重新序列化.

问题

我们不会在Hadoop作业中明确使用Kryo,而是通过我们自己的图书馆的多个层访问它.对于每个这些库,都是必要的

>重命名涉及包和

>创建具有不同组或工件ID的版本

为了使事情更加凌乱,我们还使用其他第三方库提供的Kryo序列化程序,我们必须做同样的事情.

(2)使用多个类装载器

我们想出的第二种方法是在包含转换作业的Maven项目中完全不依赖于Kryo,而是从存储在Hadoop分布式缓存中的每个版本的JAR加载所需的类.序列化一个对象然后将看起来像这样:

public byte[] serialize(Object foo, JarClassLoader cl) {

final Class> kryoClass = cl.loadClass("com.esotericsoftware.kryo.Kryo");

Object k = kryoClass.getConstructor().newInstance();

ByteArrayOutputStream baos = new ByteArrayOutputStream();

final Class> outputClass = cl.loadClass("com.esotericsoftware.kryo.io.Output");

Object output = outputClass.getConstructor(OutputStream.class).newInstance(baos);

Method writeObject = kryoClass.getMethod("writeObject", outputClass, Object.class);

writeObject.invoke(k, output, foo);

outputClass.getMethod("close").invoke(output);

baos.close();

byte[] bytes = baos.toByteArray();

return bytes;

}

问题

虽然这种方法可能有助于实例化未配置的Kryo对象并序列化/恢复某些对象,但我们使用更复杂的Kryo配置.这包括几个自定义序列化程序,注册的类别等等.例如,我们无法找出一种方法来为类设置自定义序列化,而不会得到NoClassDefFoundError – 以下代码不起作用:

Class> kryoClass = this.loadClass("com.esotericsoftware.kryo.Kryo");

Object kryo = kryoClass.getConstructor().newInstance();

Method addDefaultSerializer = kryoClass.getMethod("addDefaultSerializer", Class.class, Class.class);

addDefaultSerializer.invoke(kryo, URI.class, URISerializer.class); // throws NoClassDefFoundError

最后一行抛出一个

java.lang.NoClassDefFoundError: com/esotericsoftware/kryo/Serializer

因为URISerializer类引用了Kryo的Serializer类,并尝试使用它自己的类加载器(它是System类加载器)加载它,它不知道Serializer类.

(3)使用中间序列化

目前最有希望的方法似乎是使用独立的中间序列化,例如JSON使用Gson或类似的,然后运行两个单独的作业:

> kryo:2.21.2-ourpatchbranch在我们的常规商店 – > JSON在临时商店

>临时商店中的JSON – > kryo:2-22在我们的常规商店

问题

这个解决方案最大的问题是它大大加倍了处理的数据的空间消耗.此外,我们需要另一个序列化方法,在我们所有的数据上都没有问题,我们首先需要进行调查.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值