• Clickhouse写入问题汇总


    Clickhouse写入问题汇总

    Zookeeper相关

    当clickhouse在建表时使用了Replicated引擎族时, 会对zookeeper有非常重的依赖, 这时候就要注意zookeeper集群的一些优化项.

    clickhouse集群两分片两副本(4C8G),实测每分钟80W数据量的情况下, Zookeeper单机(4C8G)完全就能够满足要求了, 甚至还有很大的余地.

    1. 修改zookeeper的配置项

      具体的参数说明可以看官网 Clickhouse Settings

      clientPort=2181
      dataDir=/data/zookeeper
      dataLogDir=/data/logs/zookeeper
      tickTime=2000
      initLimit=30000
      syncLimit=10
      maxClientCnxns=2000
      maxSessionTimeout=60000000
      autopurge.snapRetainCount=10
      autopurge.purgeInterval=1
      preAllocSize=131072
      snapCount=3000000
      leaderServes=yes
      standaloneEnabled=false
      server.1=172.16.8.132:2888:3888
      
    2. Zookeeper相关文件的存放

      • zookeeper的snapshot文件存储盘不低于1T, 注意清理策略.
      • 将dataLogDir存放目录应该与dataDir分开, 可单独采用一套存储设备来存放ZK日志, 最好用SSD.
    3. 多套Zookeeper集群配置一套Clickhouse集群.

    1. Code 999

    com.dtstack.jlogstash.outputs.core.common.ClickhouseException: ru.yandex.clickhouse.except.ClickHouseException: ClickHouse exception, code: 999, host: 172.16.8.84, port: 8123; Code: 999, e.displayText() = DB::Exception: Cannot allocate block number in ZooKeeper: Coordination::Exception: Connection loss (version 19.14.6.12)
    

    ck与Zookeeper的连接丢失导致不能分配块号等问题.

    在Clickhouse中, 表的元数据信息, 每个数据块的信息, 每次插入的时候, 数据同步的时候, 都需要和zookeeper进行交互. zookeerper 服务在同步日志过程中, 会导致ZK无法响应外部请求, 进而引发session过期等问题.

    解决方法

    1. 参考上面zookeeper相关的优化.

    2. zoo.cfg中增加forceSync=no

      默认是开启的, 为避免同步延迟问题, zk接收到数据后会立刻去将当前状态信息同步到磁盘日志文件中, 同步完成后才会应答. 将此项关闭后,客户端连接可以得到快速响应.

      关闭forceSync选项后, 会存在潜在风险, 虽然依旧会刷磁盘(log.flush()首先被执行), 但因为操作系统为提高写磁盘效率, 会先写缓存. 当机器异常后, 可能导致一些zk状态信息没有同步到磁盘, 从而带来zkl前后信息不一样问题.

    3. clickhouse建表的时候添加use_minimalistic_part_header_in_zookeeper参数, 对元数据进行压缩存储, 但是修改完了以后无法再回滚的.

    Code 225

    com.dtstack.jlogstash.outputs.core.common.ClickhouseException: ru.yandex.clickhouse.except.ClickHouseException: ClickHouse exception, code: 225, host: 172.16.8.84, port: 8123; Code: 225, e.displayText() = DB::Exception: ZooKeeper session has been expired. (version 19.14.6.12)
    

    zk会话超时, 一般都是由于zk单机/集群出问题(例如zk服务挂了, zk的压力太大)导致的.

    解决方法

    1. 参考上面zookeeper相关的优化.
    2. zk client在与所有server断开连接后(有可能是各种原因), client 会收到 disconnted消息. 当zk server 恢复后, zk client会自动与server连接上, 但是此时会话已失效, client收到 session expired消息. 前一个会话的所有数据均丢失. 接下来你要怎么做, 得看你的程序用途:
      • 如果只是读写, 没有主备机切换情况(就是当一台主机一台备机, 当主机挂机时, zk通知备机成为主机), 那么, 重新new一个会话, 将原来session的树状结构重新建立起来就行了.
      • 如果是主备机切换情况, 那就不能简单的建立 树状结构, 因为这时我们是不知道到底主机是挂掉了, 还是session expired了. 就只能把它当作真的是主机挂机来处理.
    3. ZK所有集群均不可用情况是比较少见的, 但是session expired需要引起重视起来.
    4. 一般情况下, 集群中一两台机器的挂机和启动, 我们都不用关心, apache的zk client可以帮我们自动处理这些问题.

    Code 242

    com.dtstack.jlogstash.outputs.core.common.ClickhouseException: ru.yandex.clickhouse.except.ClickHouseException: ClickHouse exception, code: 242, host: 172.16.8.84, port: 8123; Code: 242, e.displayText() = DB::Exception: Table is in readonly mode (version 19.14.6.12)
    

    zookeeper压力太大, 表处于“read only mode”模式, 导致插入失败.

    解决方法

    其实和上面两个问题Code 999/225一样, 都是由于zk集群的配置导致的, 所以只要想办法增加zk集群的配置, 或者降低zk集群的压力即可.

    1. 参考上面zookeeper相关的优化.

    Code 1002

    com.dtstack.jlogstash.outputs.core.common.ClickhouseException: ru.yandex.clickhouse.except.ClickHouseUnknownException: ClickHouse exception, code: 1002, host: 172.16.8.84, port: 8123; 172.16.8.84:8123 failed to respond
    

    导致的原因是官方jdbc的实现用了httpclient的库.
    服务器的keep-alive时间已知为3s, 客户端与服务端进行通信, httpclient会复用已创建的连接, 若服务端已关闭连接, 客户端在沿用这个连接就会出现failed to respond的错误.

    解决方法

    1. 禁用HttpClient的连接复用.
    2. 重试方案: http请求使用重发机制, 捕获NohttpResponseException的异常, 重新发送请求,重发N次后还是失败才停止.
    3. 根据keep Alive时间, 调整validateAfterInactivity小于keepAlive Time, 但这种方法依旧不能避免同时关闭.
    4. 系统主动检查每个连接的空闲时间, 并提前自动关闭连接. 避免服务端主动断开.

    对于clickhouse的jdbc来说, 如果要提供方案, 就要在源码层面更改:

    • 方案1: 修改为短连接, 当然这种方式看你接不接受了, ClickHousePreparedStatementImpl中设置:

      post.setHeader("Connection", "close");
      
    • 方案2: 引入重试机制, 当出现这种错误的时候, 莫急莫慌, 再试一次.

    这里我们采用的是方案2, 使用重试机制, 具体的重试次数可以通过参数bulkRetries来控制.

    推荐Insert操作使用方案2, Select操作使用方案1. 不需要考虑多次Insert同一数据导致数据重复的问题, CH内部有机制来保证数据唯一性.

    Code 371

    问题描述

    An error occured before execution: Code: 371, e.displayText() = DB::Exception: Table 'test01' isn't replicated, but shard #1 is replicated according to its cluster definition (version 19.14.6.12)
    

    只有使用了replicated开头的engine的引擎的表, 才能够在拥有on cluster xxx条件的ddl语句中进行集群更新
    其他engine的表, 只能够每个node进行update.
    distributed_table使用的是Distributed引擎, 所以也不支持on cluster xxx这样条件的ddl语句.

    但是在最近的版本中(v20.8 LTS)中, Distributed引擎也支持了 on cluster 操作了, 感觉在低版本中不支持集群DDL语句可能是一个BUG.

    所以建议条件允许的话, 将CH集群升级到20.8及以上版本即可.

    解决方法

    如果是分布式表

    • 每个节点执行语句

    如果是local表

    • 每个节点执行语句
    • 换用replicated的表引擎

    Code 48

    ClickHouse exception, code: 48, host: 172.16.8.84, port: 8123; Code: 48, e.displayText() = DB::Exception: There was an error on [172.16.8.84:9000]: Cannot execute replicated DDL query on leader (version 19.14.6.12)
    

    这个问题我自己也没有弄明白, 查了非常多的资料, 各执一词. 在20.4及以后版本的一个pr修复了相关的问题:

    Fix DDL worker timeouts for long queries

    推荐升级到v20.8LTS版本.

    如果不支持升级CH版本, 我尝试在低版本上为每个分片加了一个副本也将这个问题解决了(原先的架构是无副本的).

  • 相关阅读:
    java虚拟机字节码执行引擎
    java7 invokedynamic命令深入研究
    [转载]使用expect实现shell自动交互
    elasticsearch 聚合时 类型转换错误
    ES的关键端口
    CentOS6.5安装ganglia3.6
    Linux远程执行echo问题
    [转载]CentOS修改用户最大进程数
    elasticsearch新加入节点不能识别问题
    ssh免密码登录的注意事项
  • 原文地址:https://www.cnblogs.com/yisany/p/14275785.html
Copyright © 2020-2023  润新知