2015-03-31 171 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