• 解决 clickhouse jdbc 偶现 failed to respond 问题


    背景

    Clickhouse集群版本为 Github Clickhouse 22.3.5.5, clickhouse-jdbc 版本为 0.2.4

    问题表现

    随着业务需求的扩展,基于Clickhouse 需要支持更多任务在期望的时效内完成,于是将业务系统和Clickhouse交互的部分都提交给可动态调整核心参数的线程池去执行,尽量可控的利用Clickhouse集群的计算资源。

    然后一测试就出现了高频的异常:ru.yandex.clickhouse.except.ClickHouseUnknownException: ClickHouse exception, code: 1002, host: 192.168.1.1, port: 8123; 192.168.1.1:8123 failed to respond

    搜索发现有比较多类似问题


    解决经历

    首先问题就指向了驱动版本, 社区在0.2.5优化了这个问题, 那就只能升级驱动版本了, 由于这个项目也是接手的,通常来说遇到性能问题,不会第一时间考虑升级依赖版本除非找到确认的依据是版本有缺陷,因为风险不可控.

    但是社区还有类似问题反馈,BatchUpdateException during inserts with jdbc driver 于是直接跨多个版本升到了0.6.0

    升级后使用线程池跑确实就不会出现高频的报错了,但是仍偶现有1002报错,当时加了重试逻辑,赶业务进度,测试后就上线了,但是遇到了一个不大不小的坑: Druid管理的JDBC Connection 在调用getConnection().getSchema(); 时,0.2.4版本的驱动正常返回了连接所在的数据库名,但是0.6.0返回了null,导致部分业务场景出错了,只好紧急修复了,原因是因为com.clickhouse.jdbc.JdbcConfig#databaseTerm 的值默认是catalog模式,要改成shcema模式才会返回数据库名 jdbc url后追加参数 databaseTerm=schema
    在这里插入图片描述

    Clickhouse 里对于JDBC 中catalog 和 schema 的实现 都是作为 数据库的别名。

    过了一段时间,业务又发生了扩展,要跑的任务更多了,每到高频的跑任务时,就可能会看到告警群会来几条1002的报错告警。然后开始新一轮找问题了. 最终多轮压测调试结论如下。


    1. socket_timeout

    由于升级驱动到0.6.0时也调整了JDBC的参数, 那时只看到了客户端的值远大于服务端的值,就只想着尽量复用连接少建立连接的开销实际上不是重点,就把驱动的socket_timeout 设置为了和服务端的 tcp_keep_alive_timeout保持一致为 290s,(注意默认值是3s 部署时调整了参数 )。

    实际上连接的活跃性和socket_timeout 没有关系,见下文,当长时间执行的DDL和查询会报错 Read timeout http read timeout 30, 因此socket_timeout设置为业务合理值即可。

    注意 socket_timeout 的默认值及实现机制均由驱动实现,MySQL PostgreSQL Clickhouse 等均不同,此处Clickhouse 0.6.0 的驱动内 socket_timeout 默认值为30S在这里插入图片描述

    2. 连接 keepalive

    通过这个PR Validate stale connection to fix the bug: failed to respond 注意到项目内没有设置合理的连接保活机制。

    按这个场景来说,当客户端的一个连接到了超时的边界值时,考虑到网络延迟,客户端会认为是有效的,但是服务端认为超时了,就会关闭连接, 就又会抛出1002了,如果SQL的提交是低频的就不容易出现这个情况,当有多个线程并发跑1小时以上时概率就大大增加了,此时需要加入连接的心跳机制规避服务端关闭不活跃连接的情况。

    BatchUpdateException during inserts with jdbc driver

    在这里插入图片描述依据开发者的建议,我们将心跳检查的周期设置的比tcp_keep_alive_timeout的290更小,例如120s。

    例如Druid连接池 通过如下参数开启

          # 心跳保活
          keepAlive: true
          # 心跳保活间隔,keepAlive开启才生效
          keepAliveBetweenTimeMillis: 120000
          # 配置检测连接是否有效 创建连接和心跳保活时执行 检查sql 通常默认是 select 1 或原生支持ping协议包(MySQL Oracle). 
          validationQuery: SELECT 1
    

    两项调整后,目前1002问题尚未出现

  • 相关阅读:
    Xilinx 7系列 clock IP核的使用(一)
    基于拟蒙特卡洛模拟法的随机潮流计算matlab程序
    彻底搞懂blob对象,实现文件下载,文件分片技术
    C++二分算法: 找出第 K 小的数对距离
    基于C/C++的UG二次开发流程
    Paradigm 介绍 Goldfish:PoS 以太坊中 LMD GHOST 分叉规则的安全替代品
    @Transaction注解的应用
    CAA的VS Studio安装
    zookeeper集群
    VSCode 配置 Spring Boot 项目开发环境
  • 原文地址:https://blog.csdn.net/kcp606/article/details/139455466