一旦一个节点关闭,Cassandra 3 节点集群就会抛出 NoHostAvailableException
Cassandra 3 nodes cluster throwing NoHostAvailableException as soon as one node is down
我们有一个带有 RF 3 的 3 节点集群。
一旦我们从集群中排出一个节点,我们就会看到很多:
All host(s) tried for query failed (no host was tried)
com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (no host was tried)
at com.datastax.driver.core.exceptions.NoHostAvailableException.copy(NoHostAvailableException.java:84)
at com.datastax.driver.core.DriverThrowables.propagateCause(DriverThrowables.java:37)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:214)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:52)
我们所有的写入和读取都具有一致性级别 QUORUM 或 ONE,因此在一个节点关闭时一切都应该完美运行。但是只要节点宕机,就会抛出异常。
我们使用 Cassandra 2.2.4 + Java Cassandra Driver 2.1.10.2
以下是我们创建集群的方式:
new Cluster.Builder()
.addContactPoints(CONTACT_POINTS)
.withCredentials(USERNAME, PASSWORD)
.withRetryPolicy(new LoggingRetryPolicy(DefaultRetryPolicy.INSTANCE))
.withReconnectionPolicy(new ExponentialReconnectionPolicy(10, 10000))
.withLoadBalancingPolicy(new TokenAwarePolicy(new RoundRobinPolicy()))
.withSocketOptions(new SocketOptions().setReadTimeoutMillis(12_000))
.build();
CONTACT_POINTS 是节点的 3 public ips 的字符串数组。
几个月前,集群在暂时只有 2 个节点的情况下工作正常,但由于未知原因,情况不再如此,我 运行 没有想法:(
非常感谢您的帮助!
问题已解决。
更多分析表明问题出在IP问题上。我们的 cassandra 服务器使用私有本地 IP (10.0.) 进行通信,而我们的应用服务器在其配置中具有 public IP。
当他们在同一网络中时,它工作正常,但当他们移动到不同的网络时,他们只能连接到集群中的一台机器,而另外两台机器被认为已关闭,因为他们正在尝试连接到私有本地 IP,而不是 public 一个用于另外两个。
解决方案是在集群构建器中添加一个 IPTranslater:
.withAddressTranslater(new ToPublicIpAddressTranslater())
使用以下代码:
private static class ToPublicIpAddressTranslater implements AddressTranslater {
private Map<String, String> internalToPublicIpMap = new HashMap<>();
public ToPublicIpAddressTranslater() {
for (int i = 0; i < CONTACT_POINT_PRIVATE_IPS.length; i++) {
internalToPublicIpMap.put(CONTACT_POINT_PRIVATE_IPS[i], CONTACT_POINTS[i]);
}
}
@Override
public InetSocketAddress translate(InetSocketAddress address) {
String publicIp = internalToPublicIpMap.get(address.getHostString());
if (publicIp != null) {
return new InetSocketAddress(publicIp, address.getPort());
}
return address;
}
}
我们有一个带有 RF 3 的 3 节点集群。
一旦我们从集群中排出一个节点,我们就会看到很多:
All host(s) tried for query failed (no host was tried)
com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (no host was tried)
at com.datastax.driver.core.exceptions.NoHostAvailableException.copy(NoHostAvailableException.java:84)
at com.datastax.driver.core.DriverThrowables.propagateCause(DriverThrowables.java:37)
at com.datastax.driver.core.DefaultResultSetFuture.getUninterruptibly(DefaultResultSetFuture.java:214)
at com.datastax.driver.core.AbstractSession.execute(AbstractSession.java:52)
我们所有的写入和读取都具有一致性级别 QUORUM 或 ONE,因此在一个节点关闭时一切都应该完美运行。但是只要节点宕机,就会抛出异常。
我们使用 Cassandra 2.2.4 + Java Cassandra Driver 2.1.10.2
以下是我们创建集群的方式:
new Cluster.Builder()
.addContactPoints(CONTACT_POINTS)
.withCredentials(USERNAME, PASSWORD)
.withRetryPolicy(new LoggingRetryPolicy(DefaultRetryPolicy.INSTANCE))
.withReconnectionPolicy(new ExponentialReconnectionPolicy(10, 10000))
.withLoadBalancingPolicy(new TokenAwarePolicy(new RoundRobinPolicy()))
.withSocketOptions(new SocketOptions().setReadTimeoutMillis(12_000))
.build();
CONTACT_POINTS 是节点的 3 public ips 的字符串数组。
几个月前,集群在暂时只有 2 个节点的情况下工作正常,但由于未知原因,情况不再如此,我 运行 没有想法:(
非常感谢您的帮助!
问题已解决。
更多分析表明问题出在IP问题上。我们的 cassandra 服务器使用私有本地 IP (10.0.) 进行通信,而我们的应用服务器在其配置中具有 public IP。
当他们在同一网络中时,它工作正常,但当他们移动到不同的网络时,他们只能连接到集群中的一台机器,而另外两台机器被认为已关闭,因为他们正在尝试连接到私有本地 IP,而不是 public 一个用于另外两个。
解决方案是在集群构建器中添加一个 IPTranslater:
.withAddressTranslater(new ToPublicIpAddressTranslater())
使用以下代码:
private static class ToPublicIpAddressTranslater implements AddressTranslater {
private Map<String, String> internalToPublicIpMap = new HashMap<>();
public ToPublicIpAddressTranslater() {
for (int i = 0; i < CONTACT_POINT_PRIVATE_IPS.length; i++) {
internalToPublicIpMap.put(CONTACT_POINT_PRIVATE_IPS[i], CONTACT_POINTS[i]);
}
}
@Override
public InetSocketAddress translate(InetSocketAddress address) {
String publicIp = internalToPublicIpMap.get(address.getHostString());
if (publicIp != null) {
return new InetSocketAddress(publicIp, address.getPort());
}
return address;
}
}