java - 如何快速查看RMI注册表?

标签 java rmi rmiregistry

我正在尝试为分布式系统项目实现 Raft 共识算法。

我需要一些非常快速的方法来知道服务器 A 是否可以从服务器 B 访问并且 A 的分布式系统是否已启动。换句话说,可能会出现B可以访问A但A的云系统尚未启动的情况。所以我认为 InetAddress.getByName(ip).isReachable(timeout); 还不够。

由于每个服务器的 stub 都被重命名为服务器的名称,所以我想获取服务器的注册表,然后检查是否存在与服务器同名的 stub :如果不存在,则跳到下一个服务器,否则执行查找(这可能需要很长时间)。这是代码的一部分:

try {
    System.out.println("Getting "+clusterElement.getId()+"'s registry");
    Registry registry = LocateRegistry.getRegistry(clusterElement.getAddress());
    System.out.println("Checking contains:");
    if(!Arrays.asList(registry.list()).contains(clusterElement.getId())) {
        System.out.println("Server "+clusterElement.getId()+" not bound (maybe down?)!");
        continue;
    }
    System.out.println("Looking up "+clusterElement.getId()+"'s stub");
    ServerInterface stub = (ServerInterface) registry.lookup(clusterElement.getId());
    System.out.println("Asking vote to "+clusterElement.getId());
    //here methods are called on stub (exploiting costum SocketFactory)
} catch (NoSuchObjectException | java.rmi.ConnectException | java.rmi.ConnectIOException e){
    System.err.println("Candidate "+serverRMI.id+" cannot request vote to "+clusterElement.getId()+" because not reachable");
} catch (UnmarshalException e) {
    System.err.println("Candidate " + serverRMI.id + " timeout requesting vote to " + clusterElement.getId());
} catch (RemoteException e) {
    e.printStackTrace();
} catch (NotBoundException e) {
   System.out.println("Candidate "+serverRMI.id+" NotBound "+clusterElement.getId());
}

现在的问题是服务器卡在 contains() 行,因为打印了消息 Checking containsLooking up... 则没有。

为什么会发生这种情况?有什么办法可以加快这个过程吗?该算法完全超时,因此任何建议将不胜感激!

更新: 在尝试了有关 RMI 超时的所有可能的 VM 属性后,例如: -Dsun.rmi.transport.tcp.responseTimeout=1 -Dsun.rmi.transport.proxy.connectTimeout=1 -Dsun.rmi.transport.tcp.handshakeTimeout=1 即使每个 RMI 操作都应该抛出异常(因为每个超时设置为 1 毫秒!),我也没有看到任何差异。

我找到的解决此问题的唯一解决方案是使用此 RMISocketFactory 重新实现:

final int timeoutMillis = 100;            
RMISocketFactory.setSocketFactory( new RMISocketFactory()
            {
                public Socket createSocket( String host, int port )
                        throws IOException
                {
                    Socket socket = new Socket();
                    socket.setSoTimeout(timeoutMillis);
                    socket.connect(new InetSocketAddress(host, port), timeoutMillis);
                    return socket;
                }

                public ServerSocket createServerSocket( int port )
                        throws IOException
                {
                    return new ServerSocket( port );
                }
            } );

最佳答案

它卡在Registry.list()中。它最终会超时。

您最好只调用 lookup() 而无需执行此先前步骤(这不会增加任何值),并调查从 RMI 主页链接的两个属性页面中提到的所有超时选项。

关于java - 如何快速查看RMI注册表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29364494/

相关文章:

java - 在 Java 8 默认接口(interface)方法上使用 Spring @Transactional 注释是否安全?

java - 远程和动态代理

java.rmi.server.codebase 在 linux 上不工作

java - LocateRegistry.createRegistry() 不能使应用程序保持 Activity 状态

java - 如何将对象绑定(bind)到 Swing 表中的一行?

java - JavaFX 中使用 afterburner fx 进行页面导航和值传递?

java - 在 Java 中避免依赖 hell 的首选步骤是什么?

java - 用 Java 实现 IM 平台

java - 运行java应用程序而不启动rmiregistry

Java RMI 在没有绑定(bind)的情况下返回对远程对象的引用