Scala多参数列表样例类作为Ignite缓存键未命中问题咨询
问题根源
Apache Ignite默认使用BinaryMarshaller序列化缓存键,它会扫描并序列化对象的所有字段(包括你定义的第二个参数列表中的ex1、ex2,哪怕这些字段是Scala case class非主构造参数的私有成员)。
Ignite在缓存查找时,会基于序列化后的BinaryObject计算哈希值并判断相等性,而不是直接调用Scala case class生成的hashCode()和equals()方法。这就导致:即使两个CacheKey对象在Scala层面因p1、p2相同而判定相等,但它们的BinaryObject会因ex1、ex2值不同被视为完全不同的键,最终缓存无法命中。
解决方案
针对这个问题,有几种可行的处理方式:
1. 自定义BinarySerializer(推荐)
为CacheKey编写自定义序列化器,仅序列化主构造参数p1、p2,忽略ex1、ex2,让Ignite的BinaryObject仅基于主键字段生成:
import org.apache.ignite.binary.{BinaryReader, BinaryWriter, BinarySerializer} class CacheKeyBinarySerializer extends BinarySerializer { override def write(obj: AnyRef, writer: BinaryWriter): Unit = { val key = obj.asInstanceOf[CacheKey] writer.writeString("p1", key.p1) writer.writeString("p2", key.p2) // 不序列化ex1、ex2 } override def read(clazz: Class[_], reader: BinaryReader): AnyRef = { val p1 = reader.readString("p1") val p2 = reader.readString("p2") // 反序列化时ex1、ex2设为默认值 CacheKey(p1, p2)(null, null) } }
然后在Ignite配置中注册该序列化器:
import org.apache.ignite.configuration.{BinaryConfiguration, IgniteConfiguration} val igniteCfg = new IgniteConfiguration() val binaryCfg = new BinaryConfiguration() binaryCfg.setSerializer(classOf[CacheKey], new CacheKeyBinarySerializer()) igniteCfg.setBinaryConfiguration(binaryCfg)
2. 切换为Java序列化(仅测试/小集群场景)
禁用BinaryMarshaller,改用Java原生序列化(性能较差,不推荐生产环境使用):
import org.apache.ignite.marshaller.jdk.ObjectInputStreamMarshaller import org.apache.ignite.configuration.IgniteConfiguration val igniteCfg = new IgniteConfiguration() igniteCfg.setMarshaller(new ObjectInputStreamMarshaller())
3. 重构键结构
将ex1、ex2从缓存键中分离,改为通过Ignite的上下文传递(比如使用EntryProcessor或自定义CacheStore上下文),但这种方式需要修改CacheStore的实现逻辑,适合对键结构有严格规范的场景。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

