一个节点关闭后,Cassandra 3节点集群抛出NoHostAvailableException

时间:2016-06-17 12:36:34

标签: cassandra cassandra-2.2

我们有一个带有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个公共节点的String数组。

几个月前,群集只能暂时只有2个节点工作正常但由于一个未知的原因,情况不再如此,我的想法已经不多了:(

非常感谢你的帮助!

1 个答案:

答案 0 :(得分:0)

问题解决了。

更多分析显示该问题来自IP问题。我们的cassandra服务器使用专用本地IP(10.0。)进行通信,而我们的应用服务器在其配置中具有公共IP。

当他们在同一个网络中时,它工作正常,但当他们移动到不同的网络时,他们只能连接到群集中的一台机器,而另外两台机器在他们尝试连接时被视为关闭私有的本地IP而不是其他两个的公共IP。

解决方案是在集群构建器中添加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;
    }
}