如何快速查看RMI注册表?
How to quickly check RMI registry?
我正在尝试为分布式系统项目实施 Raft 共识算法。
我需要一些非常快速的方法来知道服务器 A 是否可以从服务器 B 访问并且 A 的分布式系统是否已启动。换句话说,B 可以访问 A 但 A 的云系统尚未启动。所以我认为 InetAddress.getByName(ip).isReachable(timeout);
是不够的。
由于每个服务器的存根都被重命名为服务器的名称,所以我想到了获取服务器的注册表,然后检查是否存在与服务器同名的存根:如果没有,则跳到下一个服务器,否则执行 lookup
(这可能需要很长时间)。这是代码的一部分:
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 contains
而 Looking up...
没有。
为什么会这样?有什么办法可以加快这个过程?该算法 FULL 超时,因此非常感谢任何建议!
更新:
在尝试了关于 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 主页链接的两个属性页面中提到的所有超时选项。
我正在尝试为分布式系统项目实施 Raft 共识算法。
我需要一些非常快速的方法来知道服务器 A 是否可以从服务器 B 访问并且 A 的分布式系统是否已启动。换句话说,B 可以访问 A 但 A 的云系统尚未启动。所以我认为 InetAddress.getByName(ip).isReachable(timeout);
是不够的。
由于每个服务器的存根都被重命名为服务器的名称,所以我想到了获取服务器的注册表,然后检查是否存在与服务器同名的存根:如果没有,则跳到下一个服务器,否则执行 lookup
(这可能需要很长时间)。这是代码的一部分:
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 contains
而 Looking up...
没有。
为什么会这样?有什么办法可以加快这个过程?该算法 FULL 超时,因此非常感谢任何建议!
更新:
在尝试了关于 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 主页链接的两个属性页面中提到的所有超时选项。