【问题标题】:Retry connection to Cassandra node upon startup启动时重试连接到 Cassandra 节点
【发布时间】:2016-12-08 00:17:57
【问题描述】:

我想使用 Docker 来启动我的应用程序和 Cassandra 数据库,并且我想为此使用 Docker Compose。不幸的是,Cassandra 的启动速度比我的应用程序慢得多,并且由于我的应用程序急切地初始化 Cluster 对象,我得到以下异常:

com.datastax.driver.core.exceptions.NoHostAvailableException: All host(s) tried for query failed (tried: cassandra/172.18.0.2:9042 (com.datastax.driver.core.exceptions.TransportException: [cassandra/172.18.0.2:9042] Cannot connect))
    at com.datastax.driver.core.ControlConnection.reconnectInternal(ControlConnection.java:233)
    at com.datastax.driver.core.ControlConnection.connect(ControlConnection.java:79)
    at com.datastax.driver.core.Cluster$Manager.init(Cluster.java:1454)
    at com.datastax.driver.core.Cluster.init(Cluster.java:163)
    at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:334)
    at com.datastax.driver.core.Cluster.connectAsync(Cluster.java:309)
    at com.datastax.driver.core.Cluster.connect(Cluster.java:251)

根据堆栈跟踪和一点调试,Cassandra Java 驱动程序似乎没有将重试策略应用于初始启动。这对我来说似乎有点奇怪。有没有办法让我配置驱动程序,让它继续尝试连接到服务器,直到成功?

【问题讨论】:

  • 你只有一个 Cassandra 节点?
  • @SotiriosDelimanolis 确定;我不需要更多的本地开发和测试,至少现在是这样。

标签: java cassandra


【解决方案1】:

您应该能够在 NoHostAvailableException 上编写一些 try/catch 逻辑,以便在等待 5-10 秒后重试连接。我建议只执行几次,然后在您知道它应该在那个时间点开始的特定时间段之后引发异常。

示例伪代码

Connection makeCassandraConnection(int retryCount) {
    Exception lastException = new IllegalStateException();
    while (retryCount > 0) {
        try {
            return doConnectionStuff();
        } catch (NoHostAvailableException e) {
            lastException = e;
            retryCount--;
            Thread.sleep(TimeUnit.SECONDS.toMillis(5));
        }
    }
    throw lastException;
}

【讨论】:

  • 是的,看来这就是我必须要做的。很奇怪,驱动程序不会自动执行此操作。我可能会在他们的错误跟踪器中为此功能创建一张票。
  • 如果多个线程试图调用这个方法怎么办?所有其他线程都必须等待,这会影响性能吗?
【解决方案2】:

如果您不想更改客户端代码,并且您的客户端应用程序的 docker 容器由于错误而停止,您可以在 docker-compose 文件中为客户端应用程序使用以下属性。

restart: unless-stopped

这将重启您的客户端应用程序容器多次失败。 docker-compose.yml 文件示例:

version: '2'
services:
  cassandra:
    image: cassandra:3.5
    ports:
      - "9042:9042"
      - "9160:9160"
    environment:
      CASSANDRA_CLUSTER_NAME: demo
  app:
    image: your-app
    restart: unless-stopped

【讨论】:

  • 是的,这是一个可能的解决方案,但如果应用程序重新启动不是免费的(例如,如果它有一些初始化要做),它就不起作用。目前我的程序不需要做任何复杂的初始化,但它很有可能在未来需要类似的东西。
【解决方案3】:

无法以这种方式配置 Datastax 驱动程序。

如果这只是 Docker 的问题,并且您不希望更改代码,则可以考虑使用诸如 wait-for-it 之类的东西,这是一个简单的脚本,它将在启动应用程序之前等待 TCP 端口被监听. 9042 是 cassandra 的原生传输端口。

其他选项是discussed here in the docker documentation,但我个人只使用了等待它,但发现它在 docker 中使用 cassandra 时很有用。

【讨论】:

  • 实际上,我目前正在使用goss 来达到这个目的。除此之外,它还能够检查 TCP 端口的可用性。但是,很自然,我希望司机这样做。
【解决方案4】:

参考:https://stackoverflow.com/a/69612290/10428392

您可以像这样通过运行状况检查来修改 docker compose 文件。

version: '3.8'
services:
  applicaion-service:
    image: your-applicaion-service:0.0.1
    depends_on:
      cassandra:
        condition: service_healthy


  cassandra:
    image: cassandra:4.0.1
    ports:
      - "9042:9042"
    healthcheck:
      test: ["CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces"]
      interval: 15s
      timeout: 10s
      retries: 10

【讨论】:

    【解决方案5】:

    如果你编排了很多 docker,你应该选择一个 docker compose with depends on tag

    version: '2'
    services:
      cassandra:
        image: cassandra:3.5
        ports:
          - "9042:9042"
          - "9160:9160"
        environment:
          CASSANDRA_CLUSTER_NAME: demo
      app:
        image: your-app
        restart: unless-stopped
        depends_on:
          - cassandra
    

    【讨论】:

    • 依赖标签只等待容器启动,Cassandra本身仍然需要一些额外的时间才能启动。
    • 是的,depends_on 实际上不起作用,这是我尝试的第一件事。
    • 还有,在 docker 3 中已经移除了depends_on 的条件,所以你不能再等到 Cassandra 健康了​​span>
    【解决方案6】:

    尝试增加连接超时,这是 AWS 等上有时会发生的一件事。我认为您正在查看错误日志中的后期阶段,在某些时候它应该告诉您由于超时或无法连接的网络而无法连接,然后它将节点标记为不可用。

    使用幻像,代码如下:

    val Connector = ContactPoints(Seq(seedHost))
        .withClusterBuilder(_.withSocketOptions(
          new SocketOptions()
          .setReadTimeoutMillis(1500)
          .setConnectTimeoutMillis(20000)
        )).keySpace("bla")
    

    资源链接:

    com.datastax.driver.core.exceptions.NoHostAvailableException #445

    【讨论】:

    • Cassandra 尚未开始在 OP 的示例中侦听客户端。连接尝试将被拒绝,因为相应端口上没有任何内容正在侦听。超时不会改变这一点。
    猜你喜欢
    • 2020-07-12
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    相关资源
    最近更新 更多