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版本, 我嘗試在低版本上為每個分片加了一個副本也將這個問題解決了(原先的架構是無副本的).


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM