
本文深入探讨了Hazelcast 4.2.5版本中,当ReplicatedMap配置为InMemoryFormat.BINARY并启用统计功能时,可能出现的ClassCastException。该异常源于Hazelcast内部在收集指标时,尝试将String类型的数据强制转换为内部的HeapData格式。教程将详细分析问题根源,并提供将ReplicatedMap泛型声明为Data的解决方案,同时讨论其对应用代码的影响及相关最佳实践。
Hazelcast ReplicatedMap与ClassCastException:深入理解InMemoryFormat.BINARY
在使用hazelcast的replicatedmap时,尤其当配置了inmemoryformat.binary并启用了统计功能 (setstatisticsenabled(true)) 时,可能会遇到java.lang.classcastexception。该异常通常发生在hazelcast内部尝试收集replicatedmap的运行时指标时,日志中会显示类似以下内容:
java.lang.ClassCastException: class java.lang.String cannot be cast to class com.hazelcast.internal.serialization.impl.HeapData ... at com.hazelcast.replicatedmap.impl.ReplicatedMapService.provideDynamicMetrics(ReplicatedMapService.java:387) at com.hazelcast.replicatedmap.impl.ReplicatedMapService.getStats(ReplicatedMapService.java:357) at com.hazelcast.replicatedmap.impl.ReplicatedMapService.getLocalReplicatedMapStats(ReplicatedMapService.java:197) at com.hazelcast.replicatedmap.impl.LocalReplicatedMapStatsProvider.getLocalReplicatedMapStats(LocalReplicatedMapStatsProvider.java:85) ...
从堆栈信息可以看出,问题发生在LocalReplicatedMapStatsProvider.getLocalReplicatedMapStats方法内部,具体是在尝试获取内部数据记录的堆内存开销时。原始的Hazelcast配置示例如下:
import com.hazelcast.config.Config;import com.hazelcast.config.InMemoryFormat;import com.hazelcast.config.JoinConfig;import com.hazelcast.config.NetworkConfig;import com.hazelcast.config.ReplicatedMapConfig;import com.hazelcast.core.Hazelcast;import com.hazelcast.core.HazelcastInstance;import com.hazelcast.replicatedmap.ReplicatedMap;public class HazelcastConfigExample { private static HazelcastInstance setupHazelcastConfig() { Config config = new Config(); config.setInstanceName("rogueUsers"); NetworkConfig network = config.getNetworkConfig(); network.setPort(5701).setPortCount(20); network.setPortAutoIncrement(true); JoinConfig join = network.getJoin(); join.getMulticastConfig().setEnabled(true); HazelcastInstance hz = Hazelcast.getOrCreateHazelcastInstance(config); ReplicatedMapConfig replicatedMapConfig = config.getReplicatedMapConfig("rogueUsers"); // 关键配置:内存格式为BINARY,并启用统计 replicatedMapConfig.setInMemoryFormat(InMemoryFormat.BINARY); replicatedMapConfig.setAsyncFillup(true); replicatedMapConfig.setStatisticsEnabled(true); // 导致问题的根源之一 replicatedMapConfig.setSplitBrainProtectionName("splitbrainprotection-name"); // 问题所在:ReplicatedMap泛型声明为String, String ReplicatedMap map = hz.getReplicatedMap("rogueUsers"); // map.addEntryListener(new RogueEntryListener()); // 假设存在监听器 return hz; } public static void main(String[] args) { HazelcastInstance instance = setupHazelcastConfig(); // 可以在这里进行map操作,例如: // ReplicatedMap map = instance.getReplicatedMap("rogueUsers"); // map.put("user1", "statusA"); // System.out.println(map.get("user1")); }}
剖析问题根源:内部数据表示与统计
当ReplicatedMapConfig的inMemoryFormat设置为InMemoryFormat.BINARY时,Hazelcast会将存储在Map中的对象序列化成二进制形式,即com.hazelcast.internal.serialization.Data接口的实现类(例如HeapData)。这种格式有助于节省内存和优化网络传输。
ClassCastException的发生,是由于在LocalReplicatedMapStats类的第85行左右,Hazelcast内部在计算内存使用量时,期望获取的是HeapData类型的内部记录,但实际获取到的却是String类型,导致了强制类型转换失败。
// 简化后的内部代码逻辑,来自LocalReplicatedMapStatsboolean isBinary = (replicatedMapConfig.getInMemoryFormat() == InMemoryFormat.BINARY);if (isBinary) { // 当 isBinary 为 true 时,期望 record.getValueInternal() 返回 HeapData memoryUsage += ((HeapData) record.getValueInternal()).getHeapCost(); // <-- 异常发生处}
这意味着,尽管我们配置了InMemoryFormat.BINARY,且期望所有数据都以二进制Data的形式存储,但在某些情况下(可能与ReplicatedMap的特定实现或版本有关),当Map的泛型声明为ReplicatedMap时,Hazelcast的统计模块在尝试访问内部数据时,未能正确地将其识别为HeapData,反而得到了原始的String对象,从而引发了类型转换错误。
解决方案:调整ReplicatedMap的泛型声明
为了解决这个ClassCastException,一种有效的解决方案是显式地将ReplicatedMap的泛型类型声明为com.hazelcast.internal.serialization.Data。Data是Hazelcast内部序列化服务处理二进制形式对象的基本单元。
修改后的配置代码如下:
import com.hazelcast.config.Config;import com.hazelcast.config.InMemoryFormat;import com.hazelcast.config.JoinConfig;import com.hazelcast.config.NetworkConfig;import com.hazelcast.config.ReplicatedMapConfig;import com.hazelcast.core.Hazelcast;import com.hazelcast.core.HazelcastInstance;import com.hazelcast.replicatedmap.ReplicatedMap;import com.hazelcast.internal.serialization.Data; // 引入Data类import com.hazelcast.spi.serialization.SerializationService; // 引入SerializationServicepublic class HazelcastConfigFixedExample { private static HazelcastInstance setupHazelcastConfig() { Config config = new Config(); config.setInstanceName("rogueUsers"); NetworkConfig network = config.getNetworkConfig(); network.setPort(5701).setPortCount(20); network.setPortAutoIncrement(true); JoinConfig join = network.getJoin(); join.getMulticastConfig().setEnabled(true); HazelcastInstance hz = Hazelcast.getOrCreateHazelcastInstance(config); ReplicatedMapConfig replicatedMapConfig = config.getReplicatedMapConfig("rogueUsers"); replicatedMapConfig.setInMemoryFormat(InMemoryFormat.BINARY); replicatedMapConfig.set
以上就是解决Hazelcast ReplicatedMap中ClassCastException与BINARY内存格式的兼容性问题的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/142305.html
微信扫一扫
支付宝扫一扫