Я пытаюсь реализовать Алгоритм консенсуса Плотов для проекта распределенной системы.
Мне нужен очень быстрый способ узнать, доступен ли сервер A с сервера B и A Distributed System. Другими словами, может случиться, что A достигнут B, но облачная система A еще не поднята. Поэтому я думаю, что InetAddress.getByName(ip).isReachable(timeout);
недостаточно.
Поскольку каждый заглушка сервера переименовывается в имя сервера, я решил получить реестр сервера и проверить, существует ли заглушка с тем же именем сервера: если это не так, то перейдите к следующему серверу, в противном случае выполните lookup
(который может занять некоторое время). Это часть кода:
try {
System.out.println("Getting "+clusterElement.getId()+" 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()+" 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 contains
напечатано, а Looking up...
is not.
Почему это происходит? Есть ли способ ускорить процесс? Этот алгоритм FULL тайм-аутов, поэтому любое предложение будет действительно оценено!
UPDATE: после -Dsun.rmi.transport.tcp.responseTimeout=1 -Dsun.rmi.transport.proxy.connectTimeout=1 -Dsun.rmi.transport.tcp.handshakeTimeout=1
всех возможных свойств VM о тайм- -Dsun.rmi.transport.tcp.responseTimeout=1 -Dsun.rmi.transport.proxy.connectTimeout=1 -Dsun.rmi.transport.tcp.handshakeTimeout=1
RMI, например: -Dsun.rmi.transport.tcp.responseTimeout=1 -Dsun.rmi.transport.proxy.connectTimeout=1 -Dsun.rmi.transport.tcp.handshakeTimeout=1
Я вообще не видел никакой разницы, даже если исключение должно было быть выброшено при каждой операции RMI (так как каждый таймаут установлен на 1 мс!).
Единственное решение, которое я выяснил для этой проблемы, - это RMISocketFactory
реализация 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.
loookup
?