RMI java.rmi.NoSuchObjectException 和重并发下的端口重用

RMI java.rmi.NoSuchObjectException and Port reuse in heavy concurrency

我正在开发具有以下结构的应用程序

应用程序设计:

问题:

当我们以较少的并发执行应用程序时,它运行良好。但是当我们增加并发性时,我们开始出现以下异常 "java.rmi.NoSuchObjectException: no such object in table" 当我们从 RemoteInputStream 读取数据时出现此异常。

我已经尝试解决这个问题并专注于 RemoteInputStream 对象。我已经看到很多关于远程对象的弱引用的回复。我看过了,发现参考性在我的情况下并不弱。

我还通过增加租赁价值修改了 dfc 属性,但对我的情况没有影响。

我对这个问题的看法:

在测试过程中,我观察到如果所有端口都使用一次,则一切正常。假设如果我在池中分配 20 个端口,那么前 20 次我不会得到任何异常。当我第二次开始使用同一个端口时,我会得到异常。如果我将端口数从 20 增加到 600,那么我将不会在前 600 次出现异常。看起来端口重用存在一些问题。 在将端口整数发送回池之前,我添加了 1 分钟的等待时间。在这种情况下,我的问题大大减少了。

所以我的结论是,如果我在 MACHINE1 的端口导出一个输入流对象,例如 55800,MACHINE2 将快速读取它并且 APP1 取消导出数据并再次尝试导出另一个远程输入流对象,那么它会产生问题。

我需要各位专家对我的问题发表看法。这个问题与 TCP/IP 协议有关吗?我是否正在尝试重用在 TCP/IP 生命周期方面仍处于活动状态的同一个端口?
有什么好的方法可以解决这个问题,而不是在 returning 端口中引入等待。


在 MACHINE1 的生产环境中,我们已经分配了一定范围的端口整数。我们的应用程序只能使用此范围内的端口。防火墙为此特定范围的端口打开。所以当我们想要导出 inputStream 时,我们必须确保数据应该在允许的端口范围内导出。所以我们使用下面的代码

UnicastRemoteObject.exportObject(remoteInputStreamObj, portNo.intValue());

为此,我们开发了一个维护自由端口整数的 POOL。如果在 APP1 中创建了新线程并且有 3 XML 个文件应该在 APP2 中处理,那么 APP1 将创建一个请求对象并创建新的三个 RemoteInputStream 对象。在创建对象时,3 端口整数将从池中删除。一旦请求在 APP2 端得到处理并且 APP1 得到结果,在这种情况下,APP1 将取消导出对象并将 return Ports 整数返回到 POOL。

这里的Ports POOL表示一个整数池,它维护空闲端口整数。这个池并不意味着 RemoteInputStream 对象池。我们每次都创建 RemoteInputStream 的新实例。在 MACHINE1 中,尽管 6 个 JVM 是 运行,但我们还有另一个第 7 个 JVM,它维护端口池的单例引用。所以一个 POOL 实例由所有其他 APP1 JVM 共享。


在我们的例子中,我们有高水平的并发。除了并发,APP1的一个request可以有多个XML。在少数情况下,单个请求中可能有 25-30 个文件,需要由 MACHINE2 APP2 同时读取。在这种情况下,我们需要创建 25-30 个 RemoteInputStream 对象实例并将其放入 Request 对象中。所以在这里我们一次需要一个以上的端口。

在实际生产环境中,可能会出现Service1的50个线程同时执行,每个Request Object可能有2-3个XML个文件需要导出inputStream对象。在这种情况下,我们需要多个端口。

we starts getting following exception "java.rmi.NoSuchObjectException: no such object in table"

这个异常只有一个意思。您试图通过其对应的远程对象未被导出的存根调用远程方法。

Once the request got processed at APP2 side and APP1 got the result, in that case APP1 will unexport the object and return the Ports integer back to POOL.

而这里,如上所述,就是问题的根源。您正在取消导出对象。然后一些客户端在远程对象未被导出的存根上调用方法,所以你得到这个异常,就像上面描述的那样。

您不需要所有这些复杂性。您可以为所有 RMI 对象使用每个 JVM 的单个端口。您甚至不需要取消导出远程对象,这是导致原始问题的原因。就让他们在正常的事件过程中成为DGC吧。

扔掉所有这些,return 每个请求一个新的 RemoteInputStream