Hazelcast Java Serialization/Deserialization ArrayList 陷阱
Hazelcast Java Serialization/Deserialization ArrayList Pitfall
我已经从 Memcached 切换到 Hazelcast。过了一会儿,我注意到缓存的大小比平时大。以人为本。
所以我喜欢这样:
1. 在调用 IMap.set(key,value(ArrayList) 之前,我将值反序列化为一个大小为 128K 的文件。
2. 在 IMap.set() 被调用后,我 IMap.get() 相同的地图,突然这现在有 6 MB 大小 。
有问题的对象有很多对象,这些对象在同一结构中被多次引用。
我打开了2个二进制文件,我看到6MB的文件有很多重复的数据。 hazelcast 使用的序列化以某种方式复制了引用
所有为缓存实例化的 类 除了枚举之外都是可序列化的。
使用 Memcached 在这两种情况下值大小都是 128K。
我已经用 hazelcast 尝试过 Kryo 并没有什么区别,仍然超过 6MB
有人遇到过与 hazelcast 类似的问题吗?如果是,您是如何在不更改缓存提供程序的情况下解决此问题的。
如果有人需要,我可以提供对象结构并尝试使用非敏感数据重现它。
Hazelcast 可以配置为使用多种不同的序列化方案; Java 序列化(默认)在时间和 space 方面都是最低效的。通常选择正确的序列化策略比您可以进行的几乎任何其他优化都会带来更大的回报。
参考手册很好地概述了不同的序列化方案和所涉及的权衡。
IMDG Reference Manual v3.11 - Serialization
如果我的应用程序都是 Java,我通常会使用 IdentifiedDataSerializable,如果我需要支持跨语言客户端或对象版本控制,我通常会使用 Portable。
如果您出于某种原因需要使用 Java 序列化,您可以检查并验证 SharedObject 属性 是否设置为 true 以避免创建同一对象的多个副本。 (属性 可以通过 hazelcast.xml 中的元素设置,或者通过 SerializationConfig 对象以编程方式设置)。
我不是在假装,但在浪费了一天之后,我终于想出了一个解决这个问题的解决方案。我不能说它是一个功能还是只是一个要报告的问题。
无论如何在 Hazelcast 中,如果你在 IMap 中输入一个值作为 ArrayList,那么将按条目序列化条目。这意味着如果我们有 100 个相同实例 A 的 6K 条目,我们将有 600K 的 Hazelcast。这里有一个简短的 RAW 代码可以证明我的答案。
要通过 Java 序列化解决或避免这种情况,您应该将 ArrayList 包装到一个对象中,这样就可以了。
(仅可序列化,无其他实现)
@Test
public void start() throws Exception {
HazelcastInstance client = produceHazelcastClient();
Data data = new Data();
ArrayList<Data> datas = new ArrayList<>();
IntStream.range(0, 1000).forEach(i -> {
datas.add(data);
});
wirteFile(datas,"DataLeoBefore","1");
client.getMap("data").put("LEO", datas);
Object redeserialized = client.getMap("data").get("LEO");
wirteFile(redeserialized,"DataLeoAfter","1");
}
public void wirteFile(Object value, String key, String fileName) {
try {
Files.write(Paths.get("./" + fileName + "_" + key), SerializationUtils.serialize(((ArrayList) value)));
} catch (IOException e) {
e.printStackTrace();
}
}
我已经从 Memcached 切换到 Hazelcast。过了一会儿,我注意到缓存的大小比平时大。以人为本。
所以我喜欢这样: 1. 在调用 IMap.set(key,value(ArrayList) 之前,我将值反序列化为一个大小为 128K 的文件。 2. 在 IMap.set() 被调用后,我 IMap.get() 相同的地图,突然这现在有 6 MB 大小 。
有问题的对象有很多对象,这些对象在同一结构中被多次引用。
我打开了2个二进制文件,我看到6MB的文件有很多重复的数据。 hazelcast 使用的序列化以某种方式复制了引用
所有为缓存实例化的 类 除了枚举之外都是可序列化的。
使用 Memcached 在这两种情况下值大小都是 128K。
我已经用 hazelcast 尝试过 Kryo 并没有什么区别,仍然超过 6MB
有人遇到过与 hazelcast 类似的问题吗?如果是,您是如何在不更改缓存提供程序的情况下解决此问题的。
如果有人需要,我可以提供对象结构并尝试使用非敏感数据重现它。
Hazelcast 可以配置为使用多种不同的序列化方案; Java 序列化(默认)在时间和 space 方面都是最低效的。通常选择正确的序列化策略比您可以进行的几乎任何其他优化都会带来更大的回报。
参考手册很好地概述了不同的序列化方案和所涉及的权衡。 IMDG Reference Manual v3.11 - Serialization
如果我的应用程序都是 Java,我通常会使用 IdentifiedDataSerializable,如果我需要支持跨语言客户端或对象版本控制,我通常会使用 Portable。
如果您出于某种原因需要使用 Java 序列化,您可以检查并验证 SharedObject 属性 是否设置为 true 以避免创建同一对象的多个副本。 (属性 可以通过 hazelcast.xml 中的元素设置,或者通过 SerializationConfig 对象以编程方式设置)。
我不是在假装,但在浪费了一天之后,我终于想出了一个解决这个问题的解决方案。我不能说它是一个功能还是只是一个要报告的问题。
无论如何在 Hazelcast 中,如果你在 IMap 中输入一个值作为 ArrayList,那么将按条目序列化条目。这意味着如果我们有 100 个相同实例 A 的 6K 条目,我们将有 600K 的 Hazelcast。这里有一个简短的 RAW 代码可以证明我的答案。
要通过 Java 序列化解决或避免这种情况,您应该将 ArrayList 包装到一个对象中,这样就可以了。
(仅可序列化,无其他实现)
@Test
public void start() throws Exception {
HazelcastInstance client = produceHazelcastClient();
Data data = new Data();
ArrayList<Data> datas = new ArrayList<>();
IntStream.range(0, 1000).forEach(i -> {
datas.add(data);
});
wirteFile(datas,"DataLeoBefore","1");
client.getMap("data").put("LEO", datas);
Object redeserialized = client.getMap("data").get("LEO");
wirteFile(redeserialized,"DataLeoAfter","1");
}
public void wirteFile(Object value, String key, String fileName) {
try {
Files.write(Paths.get("./" + fileName + "_" + key), SerializationUtils.serialize(((ArrayList) value)));
} catch (IOException e) {
e.printStackTrace();
}
}