首页 > 解决方案 > Hazelcast 复制地图:内存格式和序列化

问题描述

我正在尝试根据配置检查对象的序列化/反序列Replicated MapIn-Memory-Format

基于Hazelcast文档In-Memory-Format

OBJECT(默认):数据以反序列化的形式存储。此配置是默认选择,因为数据复制主要用于高速访问。请注意,在没有 Map.put() 的情况下更改值不会反映在其他成员上,但在更改的成员上可见,以便以后访问值。

BINARY:数据以序列化的二进制格式存储,每次请求都必须反序列化。这个选项提供了更高的封装性,因为只要新更改的对象没有明确地将 Map.put() 再次放入映射中,对值的更改总是被丢弃。

示例不可变类及其自定义序列化器:

@Value
@NoArgsConstructor
@AllArgsConstructor
class MyObject {
    String str;
}
@Slf4j
class MyObjectSerializer implements ByteArraySerializer<MyObject> {
    private final ObjectMapper jsonMapper = new ObjectMapper();
    @Override
    public byte[] write(MyObject object) throws IOException {
        log.info("Serialize: {}", object);
        return jsonMapper.writeValueAsBytes(object);
    }
    @Override
    public MyObject read(byte[] buffer) throws IOException {
        MyObject obj = jsonMapper.readValue(buffer, MyObject.class);
        log.info("Deserialize {}", obj);
        return obj;
    }
    @Override
    public int getTypeId() { return 1; }
    @Override
    public void destroy() { }
}

HazelcastInstance配置和创建(使用自定义序列化程序):

private static final HazelcastInstance instance = Hazelcast.newHazelcastInstance(config());

private static Config config() {
    Config config = new Config();
    config.getSerializationConfig().addSerializerConfig(new SerializerConfig()
            .setTypeClass(MyObject.class)
            .setImplementation(new MyObjectSerializer());
    return config;
}

第一个测试(in-memory-formatobject):

@Test
public void test_put_inMemoryFormatIsObject() {
    ReplicatedMapConfig config = instance.getConfig().getReplicatedMapConfig("map1");
    config.setInMemoryFormat(InMemoryFormat.OBJECT);
    ReplicatedMap<Integer, MyObject> map = instance.getReplicatedMap("map1");
    map.put(1, new MyObject("Hi1"));
}

输出日志:

INFO HazelcastTest$MyObjectSerializer -| Serialize: HazelcastTest.MyObject(str=Hi1) 
INFO HazelcastTest$MyObjectSerializer -| Deserialize HazelcastTest.MyObject(str=Hi1) 

第二个测试(in-memory-formatbinary):

@Test
public void test_put_inMemoryFormatIsBinary() {
    ReplicatedMapConfig config = instance.getConfig().getReplicatedMapConfig("map2");
    config.setInMemoryFormat(InMemoryFormat.BINARY);
    ReplicatedMap<Integer, MyObject> map = instance.getReplicatedMap("map2");
    map.put(2, new MyObject("Hi2"));
}

输出日志:

INFO HazelcastTest$MyObjectSerializer -| Serialize: HazelcastTest.MyObject(str=Hi2) 

所以我的问题是为什么在in-memory-format = object, for eachmap.put中,对象被序列化和反序列化一次,而根本没有必要?即对象可以放入地图中,无需任何序列化和反序列化。

是否有可能改变这种行为?

注意:示例类是不可变的,我不担心修改。

标签: javahazelcast

解决方案


Hazelcast 是一个分布式数据网格,因此假设数据将分布在多个节点上。使用 IMap,对数据进行分区,以便每个节点保存一部分数据;使用 Replicated Map,每个节点都会有一个完整的副本。

即使可以将对象放入本地地图而无需序列化,也必须对数据进行序列化才能通过网络发送到其他节点。

您是只运行一个节点还是多节点集群?在序列化数据之前,我没有检查源代码以查看我们是否对单节点案例进行了任何测试。


推荐阅读