如何使用 DriverConfigLoader 增加 Cassandra Java 驱动程序中的默认超时?

How do I increase the default timeout in the Cassandra Java driver using the DriverConfigLoader?

关于 Spring Webflux Reactive Cassandra 应用程序的小问题。

在使用 Webflux 和反应式 Cassandra 的设置 Spring Boot 2.6.4 中,我正在使用该应用程序在 Cassandra 表中插入一些数据。

一切正常,直到有更高的负载时,我发现了一个问题(附加堆栈跟踪)

问题是,阅读了一些文档,我认为这段代码可以帮助解决问题:

    @Bean
    public DriverConfigLoaderBuilderCustomizer defaultProfile(){
      return builder -> builder
        .withInt(DefaultDriverOption.METADATA_SCHEMA_REQUEST_TIMEOUT, 5000)
        .build();
    }

(这是我的 Cassandra 配置,注意我使用的是 CqlSession.builder()

    protected CqlSession cqlLocalSession() {
      return CqlSession.builder()
        .addContactEndPoint(new DefaultEndPoint(new InetSocketAddress(contactPoints, port)))
        .withKeyspace(keyspace)
        .withLocalDatacenter(datacenter)
        .withAuthCredentials(username, passPhrase)
        .build();
    }

不幸的是,DriverConfigLoaderBuilderCustomizer 似乎不起作用,因为我仍然面临 PT2S 后查询超时; (我至少希望看到 PT5S。

请问是什么问题,如何正确增加超时时间?

谢谢

org.springframework.data.cassandra.CassandraUncategorizedException: ReactivePreparedStatementCallback; CQL [INSERT INTO mutable (x,y,z) VALUES (?,?,?)]; Query timed out after PT2S; nested exception is com.datastax.oss.driver.api.core.DriverTimeoutException: Query timed out after PT2S
    at org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator.translate(CassandraExceptionTranslator.java:162) ~[spring-data-cassandra-3.3.2.jar!/:3.3.2]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
    *__checkpoint ⇢ Handler myHandler [DispatcherHandler]
Original Stack Trace:
        at org.springframework.data.cassandra.core.cql.CassandraExceptionTranslator.translate(CassandraExceptionTranslator.java:162) ~[spring-data-cassandra-3.3.2.jar!/:3.3.2]
        at org.springframework.data.cassandra.core.cql.ReactiveCassandraAccessor.translate(ReactiveCassandraAccessor.java:149) ~[spring-data-cassandra-3.3.2.jar!/:3.3.2]
        at org.springframework.data.cassandra.core.cql.ReactiveCqlTemplate.lambda$translateException(ReactiveCqlTemplate.java:820) ~[spring-data-cassandra-3.3.2.jar!/:3.3.2]
        at reactor.core.publisher.Flux.lambda$onErrorMap(Flux.java:6911) ~[reactor-core-3.4.15.jar!/:3.4.15]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.4.15.jar!/:3.4.15]
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onError(ScopePassingSpanSubscriber.java:96) ~[spring-cloud-sleuth-instrumentation-3.1.1.jar!/:3.1.1]
        at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onError(MonoFlatMapMany.java:204) ~[reactor-core-3.4.15.jar!/:3.4.15]
        at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onError(FluxContextWrite.java:121) ~[reactor-core-3.4.15.jar!/:3.4.15]
        at org.springframework.cloud.sleuth.instrument.reactor.ScopePassingSpanSubscriber.onError(ScopePassingSpanSubscriber.java:96) ~[spring-cloud-sleuth-instrumentation-3.1.1.jar!/:3.1.1]
        at reactor.core.publisher.MonoCompletionStage.lambda$subscribe[=13=](MonoCompletionStage.java:80) ~[reactor-core-3.4.15.jar!/:3.4.15]
        at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088) ~[na:na]
        at com.datastax.oss.driver.internal.core.cql.CqlPrepareAsyncProcessor.lambda$process(CqlPrepareAsyncProcessor.java:71) ~[java-driver-core-4.13.0.jar!/:na]
        at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506) ~[na:na]
        at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088) ~[na:na]
        at com.datastax.oss.driver.internal.core.cql.CqlPrepareHandler.setFinalError(CqlPrepareHandler.java:320) ~[java-driver-core-4.13.0.jar!/:na]
        at com.datastax.oss.driver.internal.core.cql.CqlPrepareHandler.lambda$scheduleTimeout(CqlPrepareHandler.java:163) ~[java-driver-core-4.13.0.jar!/:na]
        at io.netty.util.HashedWheelTimer$HashedWheelTimeout.run(HashedWheelTimer.java:715) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at io.netty.util.concurrent.ImmediateExecutor.execute(ImmediateExecutor.java:34) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:703) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:790) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:503) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
        at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
Caused by: com.datastax.oss.driver.api.core.DriverTimeoutException: Query timed out after PT2S
    at com.datastax.oss.driver.internal.core.cql.CqlPrepareHandler.lambda$scheduleTimeout(CqlPrepareHandler.java:163) ~[java-driver-core-4.13.0.jar!/:na]
    at io.netty.util.HashedWheelTimer$HashedWheelTimeout.run(HashedWheelTimer.java:715) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at io.netty.util.concurrent.ImmediateExecutor.execute(ImmediateExecutor.java:34) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:703) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:790) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:503) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.74.Final.jar!/:4.1.74.Final]
    at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]

您在驱动程序上配置了错误的选项。 METADATA_SCHEMA_REQUEST_TIMEOUT 是请求检索架构的超时。

Java 驱动程序的默认请求超时为 basic.request.timeout (see reference configuration):

datastax-java-driver {
  basic.request {
    timeout = 2 seconds
  }
}

basic.request.timeout 的等效类型驱动程序选项是 REQUEST_TIMEOUT (reference TypedDriverOption.java)。

我应该指出,增加请求超时几乎永远不是处理您面临的问题的正确方法,因为您只是在隐藏问题,而没有真正解决根本原因。

正如您在 post 开头所指出的那样,当负载较高时就会出现问题。你得到 DriverTimeoutException 的原因是协调器没有及时响应,不难得出结论,这是由于节点过载。

Cassandra 中的写入非常快,因为突变附加到 commitlog 的末尾——没有磁盘寻道。如果 commitlog 的磁盘速度慢或跟不上写入,您需要查看:

  • 使用更快的磁盘,
  • 安装 commitlog 是在一个单独的 disk/volume 上,因此它不会与读取竞争相同的 IO,
  • 通过添加更多节点(将负载分散到更多节点)来增加集群的容量,或者
  • 以上所有。

您也可以通过将 DefaultDriverOption.METADATA_SCHEMA_ENABLED 设置为 false 来解决此问题。

Kotlin Reactive Data Cassandra 示例如下:

@Configuration
@EnableReactiveCassandraRepositories
    class CassandraConfiguration(
        private val cassandraProperties: CassandraProperties,
    ) : AbstractReactiveCassandraConfiguration() {
    
    ...
    ...
    
    override fun getDriverConfigLoaderBuilderConfigurer(): DriverConfigLoaderBuilderConfigurer? {
            return DriverConfigLoaderBuilderConfigurer{ builder: ProgrammaticDriverConfigLoaderBuilder ->
                builder
                    .withString(DefaultDriverOption.METADATA_SCHEMA_ENABLED, "false")
                    .build()
            }
        }
        
    }