Spring Boot+Cassandra多测试执行时出现NoNodeAvailableException求助
解决Cassandra NoNodeAvailableException问题(JUnit5+Docker Bitnami场景)
针对你在Spring Boot 2.7、JDK19环境下,JUnit5测试使用Docker部署的Bitnami Cassandra 3时,创建Keyspace阶段抛出NoNodeAvailableException的问题,可从以下几个方向排查解决:
1. 确保Cassandra容器完全就绪后再执行测试
Bitnami Cassandra镜像启动时会执行初始化脚本(创建超级用户、配置认证等),测试若在容器未完全就绪时发起请求,就会出现无可用节点的错误。
- 手动验证:执行以下命令直到成功,再启动测试:
docker exec <你的容器名> cqlsh -u cassandra -p cassandra -e "SELECT now() FROM system.local;" - 自动化等待:如果使用Testcontainers管理容器,添加健康检查等待逻辑:
@Container static CassandraContainer<?> cassandra = new CassandraContainer<>("bitnami/cassandra:3") .withExposedPorts(9042) .waitingFor(Wait.forHealthcheck());
2. 修正负载均衡策略与数据中心配置冲突
你当前使用DcInferringLoadBalancingPolicy,同时手动指定了withLocalDatacenter("datacenter1"),可能导致驱动对数据中心的判断出现冲突:
- 替换为明确的默认负载均衡策略并指定本地数据中心:
var loader = DriverConfigLoader.programmaticBuilder() .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofMinutes(1)) .withString(DefaultDriverOption.LOAD_BALANCING_POLICY_CLASS, DefaultLoadBalancingPolicy.class.getName()) .withString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, "datacenter1") .build(); - 验证容器实际数据中心名称:
确保返回值与代码中配置的docker exec <你的容器名> cqlsh -e "SELECT data_center FROM system.local;"datacenter1一致。
3. 修复Session管理的资源泄漏或并发问题
170+测试类重复创建Session,可能导致连接数耗尽或Session状态异常:
- 改用Spring托管Session:通过
@Autowired CqlSession让Spring统一管理Session生命周期,避免手动创建的隐患。 - 手动管理时添加清理逻辑:在每个测试类中添加
@AfterAll注解关闭Session:@AfterAll static void cleanupCassandraSession() { if (session != null && !session.isClosed()) { session.close(); } } - 调整驱动连接池配置:增加本地连接数上限,避免连接耗尽:
var loader = DriverConfigLoader.programmaticBuilder() // 其他配置... .withInt(DefaultDriverOption.CONNECTION_POOL_LOCAL_MAX_CONNECTIONS, 15) .build();
4. 修正认证配置逻辑
Bitnami Cassandra默认开启认证,即使本地连接也需要提供用户名密码,你当前的host判断逻辑可能导致localhost连接时未传入认证信息,被容器拒绝:
- 去掉host判断,统一使用认证信息:
var host = System.getenv("CASSANDRA_HOST") == null ? "localhost" : System.getenv("CASSANDRA_HOST"); var username = System.getenv("CASSANDRA_USER") != null ? System.getenv("CASSANDRA_USER") : "cassandra"; var password = System.getenv("CASSANDRA_PASSWORD") != null ? System.getenv("CASSANDRA_PASSWORD") : "cassandra"; - 验证容器认证配置:检查容器的
CASSANDRA_AUTH环境变量,若值为on则必须提供认证信息。
5. 强化驱动的连接与重试配置
增加连接超时和重试策略,提升网络波动下的连接稳定性:
var loader = DriverConfigLoader.programmaticBuilder() .withDuration(DefaultDriverOption.REQUEST_TIMEOUT, Duration.ofMinutes(1)) .withDuration(DefaultDriverOption.CONNECTION_CONNECT_TIMEOUT, Duration.ofSeconds(10)) .withDuration(DefaultDriverOption.CONNECTION_INIT_QUERY_TIMEOUT, Duration.ofSeconds(10)) .withString(DefaultDriverOption.RETRY_POLICY_CLASS, DefaultRetryPolicy.class.getName()) // 其他负载均衡、数据中心配置... .build();
6. 验证网络连通性
- 确认容器9042端口正确映射:执行
docker ps查看端口映射,确保是0.0.0.0:9042->9042/tcp或指定了正确的主机端口。 - 测试主机到容器的连通性:
若不通,检查防火墙、Docker网络配置是否正常。nc -zv <CASSANDRA_HOST> 9042
内容的提问来源于stack exchange,提问作者Mohamed Sweelam
相关产品推荐
相关产品推荐

