2015-03-31 126 views
1

我正在尝试为分布式系统项目实现Raft一致性算法。如何快速检查RMI注册表?

我需要一些非常快速的方法来知道服务器A是否可以从服务器B到达并且A的分布式系统已启动。换句话说,可能发生A可以通过B到达,但是A的云系统还没有到达。所以我认为InetAddress.getByName(ip).isReachable(timeout);是不够的。

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

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()); 
} 

现在的问题是服务器粘在行获取,因为打印的信息Checking containsLooking up...不是。

为什么会发生这种情况?有什么办法可以加快这个过程?这种算法是超时的完全,所以任何建议将非常感激!

UPDATE: 正在尽一切VM财产有关RMI的超时,如后: -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); 
       } 
      }); 

回答

0

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

如果没有这个前面的步骤,并没有增加任何值,并且调查从RMI主页链接的两个属性页中提到的所有超时选项,您最好只调用lookup()

+0

感谢您的回复,但我认为有关RMI属性的java文档完全是一团糟。无论如何,我更新了原始问题,包括我用来超时存根方法调用的SocketFactory。你认为这个超时是否也用于“loookup”操作? – justHelloWorld 2015-03-31 09:16:38

+0

您的套接字工厂只设置读取超时。它还需要设置连接超时,但即使如此,它也不会做任何不能被我所指的系统属性所控制的任何事情。这些文件足以让我理解它。我建议你更努力。 – EJP 2015-03-31 09:20:18

+0

好吧,通过文档我发现这三个intersting属性: 'sun.rmi.transport.proxy.connectTimeout':它似乎是我正在寻找的,因为它是关于创建套接字的超时。我不理解的部分是关于HTTP的部分。 'sun.rmi.transport.tcp.handshakeTimeout':这可能也是,但我不这么认为,因为服务器可以访问,所以TCP握手是可能的。 'sun.rmi.transport.tcp.responseTimeout':绝对不是因为它调节方法调用 – justHelloWorld 2015-03-31 09:34:03