【问题标题】:Can I (easily) use a third-party library to handle serialization for Java RMI?我可以(轻松地)使用第三方库来处理 Java RMI 的序列化吗?
【发布时间】:2011-06-20 07:01:40
【问题描述】:

我非常喜欢通过 Java 的 RMI 调用远程方法的简单性,但是它的序列化格式的冗长是一个主要的嗡嗡声(是的,我已经进行了基准测试,谢谢)。似乎 Sun 的架构师在设计 RPC(松散地说)组件时做了明显正确的事情,但在实现序列化时却遭遇了巨大的失败。

相反,似乎 Thrift、Avro、Kryo(尤其是)、协议缓冲区(不是那么多)等的架构师在设计序列化格式时通常做了明显正确的事情,但要么不提供 RPC 机制,提供一种不必要的复杂(或不成熟)的机制,或者提供一种比调用远程方法更适合数据传输的机制(对于许多目的来说非常好,但不是我想要的)。

那么,显而易见的问题是:我如何才能使用 RMI 的方法调用的可爱性,同时将上述库之一用于有线协议?这可能不需要大量工作吗?我是否过于严厉地评估上述库之一(NB 一般来说,我非常不喜欢代码生成;我有点不喜欢不必要的注释,更不喜欢 XML 配置;任何类型的“bean”都会使我畏缩——我不需要重量;理想情况下,我只想为我的远程对象实现一个接口,就像 RMI 一样。

【问题讨论】:

  • 我认为您提到的许多库(但不是 Kryo)的主要挑战是它们需要定义模式,这使得通用使用任何 POJO RPC 变得困难或不可能。
  • 快速序列化是 JDK 序列化兼容的重新实现。不过,不确定是否有必要的钩子来替换 ObjectXXXputStream 类。 github.com/RuedigerMoeller/fast-serialization

标签: java serialization rmi rpc


【解决方案1】:

Java 序列化仅在描述它正在序列化的类和字段时才比较冗长。总的来说,该格式与 XML 一样“自我描述”。您实际上可以覆盖它并用其他东西替换它。这就是 writeClassDescriptor 和 readClassDescriptor 方法的用途。 Dirmi 覆盖了这些方法,因此它能够以更少的线路开销使用标准对象序列化。

它的工作方式与其会话的工作方式有关。两个端点可能有不同版本的对象,因此简单地丢弃类描述符是行不通的。相反,会交换额外的数据(在后台),以便将序列化的描述符替换为特定于会话的标识符。在看到标识符后,检查查找表以找到描述符对象。因为数据是在后台交换的,所以在创建会话之后以及每次第一次写入对象类型时都会有一个短暂的“预热期”。

Dirmi 目前没有办法替换有线格式。

【讨论】:

    【解决方案2】:

    曾几何时,我确实有同样的要求。我已将 rmi 方法参数和返回类型更改为 byte[]。

    我使用我喜欢的序列化程序将对象序列化为字节数组,然后调用我修改后的 rmi 方法。

    好吧,正如您提到的,java 序列化过于冗长,因此 5 年前我确实实现了一种节省空间的序列化算法。如果您要发送非常复杂的对象图,它会节省太多空间。最近,我必须将此序列化实现移植到 GWT,因为在 Dev 模式下的 GWT 序列化非常慢。

    举个例子;

    rmi 方法

    public void saveEmployee(Employee emp){
      //business code
     }
    

    你应该像下面这样改变它,

    public void saveEmployee(byte[] empByte) {
            YourPreferredSerializer serialier =   YourPreferredSerializerFactory.creteSerializer();
            Employee emp = (Employee) serializer.deSerialize(empByte);
            //business code
        }
    

    编辑:

    你应该检查MessagePack。看起来很有希望。

    【讨论】:

    • 这很有趣——你能说得更详细一点吗?
    • 对于性能来说可能是合理的(在这里比较 custom 和 byte[] 与 Externalizable 可能会很有趣)但是你的远程接口变成了大量的 byte[] 可能是 anything一点也不。这绝对不会是世界上最友好的界面。
    • 嗯,你是对的。这是缺点.. :) .. 如果您有太多需要序列化的域类,则不能选择可外部化接口。
    • 这里将 custom 与 byte[] 与 Externalizable 进行比较将是一个有趣的练习,因为在每种情况下实际值写入很可能是相同的情况,但后者具有 Externalizable 的开销,因此可能是被视为更具描述性的界面的成本。然后可以决定是否值得支付这笔费用。
    • 这是迄今为止最好的答案。虽然没有从技术上回答这个问题(MessagePack 不是 RMI 并且绑定到单线协议),但它回答了问题的精神(没有臃肿的有线协议的合理 Java RPC)。如果有技术上正确的答案可用,我会接受;但是,在撰写本文时,似乎还没有这样的库。
    【解决方案3】:

    writeReplace() 和 readResolve() 可能是这样做的最佳组合。强大的力量在右手。

    【讨论】:

      【解决方案4】:

      我认为没有办法重新连接 RMI,但它可能是特定的替代项目——我特别想到 DiRMI——可能吗?和/或项目所有者可能有兴趣帮助解决此问题(其作者 Brian 是 Amazon.com 的一位非常称职的软件工程师)。

      另一个有趣的项目是Protostuff——它的作者也在构建一个RPC框架(我认为);但即使没有它也支持令人印象深刻的数据格式范围;并且非常有效地做到这一点(根据https://github.com/eishay/jvm-serializers/wiki/)。

      顺便说一句,我个人认为大多数项目(如 PB、Avro)所犯的最大错误是没有很好地将 RPC 和序列化方面分开。 因此,使用可插入数据格式或序列化提供程序执行 RPC 的能力对我来说似乎是个好主意。

      【讨论】:

      • +1 “我个人认为大多数项目(如 PB、Avro)所犯的最大错误是没有很好地分离 RPC 和序列化方面”——别再读我的想法了!
      • 可以通过实现 Externalizable 接口在某种程度上重新连接 RMI,尽管这有点侵入性。可能 rmi-iiop 也可以提供好处
      • 嗯,没错,但这只是基于每个类,而不是一般的重新布线,不能更改所有对象的数据格式。但还是有好处,在某些情况下很有用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-12
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 2019-06-21
      • 1970-01-01
      相关资源
      最近更新 更多