在Spring Boot + Cassandra中运行多个测试获得NoNodeAvailableException.&l



刚刚使用jdk19升级到Spring boot 2.7,并决定使用Cassandra bitnami 3在docker中运行,我的测试"Junit-5",我得到的错误是No node was available to execute the query,每次都发生在相同的测试用例中。

No node was available to execute the query; nested exception is 
com.datastax.oss.driver.api.core.NoNodeAvailableException: 
No node was available to execute the query
下面是我用来连接 的代码
var loader = DriverConfigLoader.programmaticBuilder()
.withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofMinutes(1))
.withString(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS,
DcInferringLoadBalancingPolicy.class.getName())
.build();
if (session == null || session.isClosed()) {
var host = System.getenv("CASSANDRA_HOST") == null ? "localhost" : System.getenv("CASSANDRA_HOST");
var username = "localhost".equals(host)? "": "cassandra";
var password = "localhost".equals(host)? "": "cassandra";
LOG.info("Cassandra host '{}'.", host);
LOG.info("Cassandra username '{}'.", username);
LOG.info("Cassandra password '{}'.", password);
var sessionBuilder = new CqlSessionBuilder()
.addContactPoint(new InetSocketAddress(host, 9042))
.withLocalDatacenter("datacenter1")
.withConfigLoader(loader);
if (!username.isEmpty()) {
sessionBuilder.withAuthCredentials(username, password);
}
session = sessionBuilder.build();

同样重要的是,我有许多170多个测试用例分布在不同的文件上,并且在每个文件执行时,我都试图使用此代码再次清理和填充DB

session.execute("create keyspace if not exists "schema_x" WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 1};");
for (final String stmt : getCassaandraStatementsFromFile(CASSANDRA_SCHEMA_FILE)) {
session.execute(stmt);
LOG.info("Cassandra. Executed statement: '{}'.", stmt.replaceAll("n", ""));
}

和错误正好发生在创建keyspace行,我试图应用一些调整从我的一边

  • 调整连接加载器并使用节流,但它没有帮助
  • 我也检查了本地数据中心的值在docker本身和匹配我的。

最后是完整的错误堆栈跟踪,如果需要的话

org.springframework.data.cassandra.CassandraConnectionFailureException: 
Query; CQL [com.datastax.oss.driver.internal.core.cql.DefaultSimpleStatement@65b70f9e]; 
No node was available to execute the query; nested exception is 
com.datastax.oss.driver.api.core.NoNodeAvailableException: 
No node was available to execute the query
at org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator.translate(CassandraExceptionTranslator.java:137)
at org.springframework.data.cassandra.core.cql.CassandraAccessor.translate(CassandraAccessor.java:422)
at org.springframework.data.cassandra.core.cql.CqlTemplate.translateException(CqlTemplate.java:764)
at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:300)
at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:320)
at org.springframework.data.cassandra.core.CassandraTemplate.select(CassandraTemplate.java:337)
at org.springframework.data.cassandra.repository.query.CassandraQueryExecution$CollectionExecution.execute(CassandraQueryExecution.java:136)
at 
...
Caused by: com.datastax.oss.driver.api.core.NoNodeAvailableException: 
No node was available to execute the query
at com.datastax.oss.driver.api.core.NoNodeAvailableException.copy(NoNodeAvailableException.java:40)
at com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures.getUninterruptibly(CompletableFutures.java:149)
at com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor.process(CqlRequestSyncProcessor.java:53)
at com.datastax.oss.driver.internal.core.cql.CqlRequestSyncProcessor.process(CqlRequestSyncProcessor.java:30)
at com.datastax.oss.driver.internal.core.session.DefaultSession.execute(DefaultSession.java:230)
at com.datastax.oss.driver.api.core.cql.SyncCqlSession.execute(SyncCqlSession.java:54)
at org.springframework.data.cassandra.core.cql.CqlTemplate.query(CqlTemplate.java:298)
... 39 common frames omitted

非常感谢您对此事的支持,提前表示感谢

Spring使用Cassandra Java驱动程序连接到Cassandra集群。

对于每个查询执行,Java驱动程序生成一个查询计划,其中包含要连接到的节点列表以执行查询。配置的负载均衡策略(在您的示例中为DcInferringLoadBalancingPolicy)确定要包含在查询计划中的节点。查询计划将只包含已知可用的节点,这意味着策略将不包括已知已关闭或被忽略的节点(详细信息请参见使用Java驱动程序进行负载平衡)。

在所有节点都被标记为"down"的场景中;或"忽略",驱动程序没有选择,因为没有可用的节点可以连接,所以驱动程序抛出NoNodeAvailableException。正如您上面发布的错误消息所述,字面上没有节点available to execute the query-正如它所说的那样。

驱动程序将节点标记为"down";或";ignored"因为它们有一段时间没有响应了通常是因为它们超载了。考虑进一步限制负载,这样节点就不会过载。

此外,模式更改不会遵循与常规写(INSERT,UPDATE,DELETE)相同的路径。每个DDL更改(CREATE,ALTER,DROP)都通过八卦协议传播到其他节点,因此根据集群的大小,集群中的所有节点可能需要一些时间才能达成模式协议。

当以编程方式执行模式更改时,不要快速连续地启动更改,否则可能会导致节点不同步。在执行下一个模式更改(例如调用isSchemaInAgreement()或异步调用checkSchemaAgreementAsync())之前,您的应用程序应该在每次模式更改后暂停并检查所有节点是否已达成模式协议。详细信息请参见与Java驱动程序的模式协议。

作为旁注,默认的cassandra超级用户不是为一般用途而设计的。它应该只用于提供另一个超级用户帐户,然后删除。

使用默认的cassandra超级用户帐户是昂贵的,因为它需要QUORUM个节点进行身份验证。相比之下,除了cassandra之外的所有帐户都以ONE的一致性进行认证。干杯!


👉请支持Apache Cassandra社区,将鼠标悬停在Cassandra标签上,然后点击Watch tag按钮。🙏谢谢!

最新更新