【问题标题】:Apache Ignite fail to serialise lambda from remote nodeApache Ignite 无法从远程节点反序列化 lambda
【发布时间】:2021-06-07 17:32:57
【问题描述】:

当我使用来自客户端节点的缓存查询扫描时出现此有线错误

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>()).getAll().stream().map(uuidAccountEntry -> uuidAccountEntry.getValue()).collect(Collectors.toList());

但如果我尝试使用过滤器仅返回对象(而不是条目),则会出现异常

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>(), Cache.Entry::getValue).getAll();

注意* 在 docker 中运行

点燃_1 | 09:54:05.663 [query-#58] 错误 o.a.i.i.b.BinaryContext - 无法反序列化对象 [typeName=java.lang.invoke.SerializedLambda] ignite_1 | org.apache.ignite.binary.BinaryObjectException:无法读取字段 [name=capturingClass] ignite_1 |在 org.apache.ignite.internal.binary.BinaryFieldAccessor.read(BinaryFieldAccessor.java:192) 点燃_1 |在 org.apache.ignite.internal.binary.BinaryClassDescriptor.read(BinaryClassDescriptor.java:875) 点燃_1 |在 org.apache.ignite.internal.binary.BinaryReaderExImpl.deserialize0(BinaryReaderExImpl.java:1764) 点燃_1 |在 org.apache.ignite.internal.binary.BinaryReaderExImpl.deserialize(BinaryReaderExImpl.java:1716) 点燃_1 |在 org.apache.ignite.internal.binary.GridBinaryMarshaller.deserialize(GridBinaryMarshaller.java:313) 点燃_1 |在 org.apache.ignite.internal.binary.BinaryMarshaller.unmarshal0(BinaryMarshaller.java:102) 点燃_1 |在 org.apache.ignite.marshaller.AbstractNodeNameAwareMarshaller.unmarshal(AbstractNodeNameAwareMarshaller.java:82) 点燃_1 |在 org.apache.ignite.internal.util.IgniteUtils.unmarshal(IgniteUtils.java:10140) 点燃_1 |在 org.apache.ignite.internal.processors.cache.query.GridCacheQueryRequest.finishUnmarshal(GridCacheQueryRequest.java:344) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager.unmarshall(GridCacheIoManager.java:1530) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager.onMessage0(GridCacheIoManager.java:576) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:380) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager.handleMessage(GridCacheIoManager.java:306) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager.access$100(GridCacheIoManager.java:101) 点燃_1 |在 org.apache.ignite.internal.processors.cache.GridCacheIoManager$1.onMessage(GridCacheIoManager.java:295) 点燃_1 |在 org.apache.ignite.internal.managers.communication.GridIoManager.invokeListener(GridIoManager.java:1569) 点燃_1 |在 org.apache.ignite.internal.managers.communication.GridIoManager.processRegularMessage0(GridIoManager.java:1197) 点燃_1 |在 org.apache.ignite.internal.managers.communication.GridIoManager.access$4200(GridIoManager.java:127) 点燃_1 |在 org.apache.ignite.internal.managers.communication.GridIoManager$9.run(GridIoManager.java:1093) 点燃_1 |在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 点燃_1 |在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 点燃_1 |在 java.lang.Thread.run(Thread.java:748)

所有其他查询和 put/get/... 工作完美,序列化 Account 对象没有问题。

我尝试了许多缓存配置,但似乎都没有任何作用。

有人遇到过这个问题或知道如何解决吗? 提前致谢。

【问题讨论】:

  • 可能是一个错误(可能是一个错误)。现在尝试使用 private static class 而不是 lambda。无论如何,这是对 Ignite 的一般建议 - lambda 序列化很奇怪,尤其是在分布式环境中,所以最好避免它。
  • 谢谢,@Stanislav 这行得通!.. 但只有在我在共享模型 jar 中创建了一个公共类之后。看我的回答。
  • 其实...如果只是将方法引用更改为 lambda 是否有效?我的意思是将Cache.Entry::getValue 更改为e -&gt; e.getValue()
  • 另外,你的 Java 版本是多少?
  • 不,我也试过了。 Java 版本:1.8.0_191,供应商:Oracle Corporation,运行时:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-11.fc29.x86_64/jre

标签: lambda ignite


【解决方案1】:

感谢来自 @Stanislav Lukyanov 的 cmets,我更改了代码并添加了一个新类,该类实现了 IgniteClosure 并作为我共享模型 jar 的一部分在所有节点上可用。

import javax.cache.Cache;
import java.util.UUID;

public class AccountValueClosure implements IgniteClosure<Cache.Entry<UUID, Account>, Account> {
    @Override
    public Account apply(Cache.Entry<UUID, Account> e) {
        return e.getValue();
    }
}

现在我可以使用闭包实例调用缓存查询...

        List<Account> data = accounts.query(new ScanQuery<UUID, Account>(), new AccountValueClosure()).getAll();

这很丑但有效。

欢迎任何反馈。

【讨论】:

    【解决方案2】:

    据我在mailing list 中读到的,ScanQuery 中的一个错误IGNITE-13212(已在v2.9 中修复)阻止在查询中使用 lambda 或匿名类。

    Ignite 团队的建议:

    由于这种特殊性,我的建议是避免使用 lambda 和匿名类。相反,您可以创建“私有静态类”,而 Ignite 将仅序列化该类的实例:

    私有静态类 MyFilter 实现 IgniteClosure { …… }

    Lamdas 非常适合演示和简单代码示例,其中 Inner/OuterClasses 是简单的 Java 类。在实际生产环境中,事情可能会变得一团糟。

    如果它没有帮助,那么您将必须确保您的过滤器/代码已部署到所有集群节点。或者您可以尝试升级到较新的版本并检查它是否可以正常工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-16
      相关资源
      最近更新 更多