7.2 客户端与驱动


7.2 客户端与驱动

本节摘要:本节讲应用怎么连 ClickHouse:原生 TCP 驱动(快)、HTTP 接口(通用)、各语言驱动选择,以及连接池和并发控制的最佳实践。

本节地图

阅读完本节,你应当能够:

  1. 区分原生协议和 HTTP 协议,选对驱动
  2. 为 Java/Python/Go 等语言选驱动
  3. 配置连接池控制并发
  4. 避免客户端侧的常见性能陷阱

一、两种连接协议

ClickHouse 有两套协议:

  • 原生 TCP 协议(端口 9000):ClickHouse 专属,二进制,效率最高。原生驱动用这个。
  • HTTP 协议(端口 8123):标准 HTTP,通用性好,几乎所有语言都能用。JDBC、HTTP 客户端走这个。

原生协议比 HTTP 快(二进制压缩、连接复用好),但只有 ClickHouse 专属驱动支持。HTTP 通用但略慢。选驱动时先看有没有你语言的原生驱动,没有就用 HTTP。

协议 端口 特点 适用
原生 TCP 9000 快、二进制 有原生驱动的语言
HTTP 8123 通用、略慢 任何语言、JDBC、curl

二、各语言驱动选择

Java

  • 官方 JDBC 驱动:走 HTTP,最通用,Spring/MyBatis 都能接。
  • clickhouse-client(Java 原生):走原生协议,更快,适合高吞吐。

生产 Java 应用大多用 JDBC,配合连接池(HikariCP)。注意 JDBC 走 HTTP,每个查询一个 HTTP 请求,高频小查询开销不小。

Python

  • clickhouse-connect:官方推荐,走 HTTP,简单好用。
  • clickhouse-driver:走原生协议,更快,适合高吞吐场景。

数据分析用 clickhouse-connect 够了;高频写入或查询用 clickhouse-driver。

Go

  • clickhouse-go:官方驱动,支持原生和 HTTP 两种协议,用 database/sql 接口。

Node.js

  • @clickhouse/client:官方驱动,走 HTTP。

三、连接池与并发控制

ClickHouse 的并发模型是"少而精"(第 2 章讲过),客户端侧要配合:

  • 连接池:复用连接,但别开太多。ClickHouse 一个连接不算重,但并发查询数要控制。
  • 并发查询数:同时跑的查询数别超过 CPU 核数太多,否则互相抢线程反而慢。
  • 批量写入:写入一定要批量,单次至少几千行,别一行一写。
# Python 批量写入示例 import clickhouse_connect client = clickhouse_connect.get_client(host='ch', port=8123) # 一次插入一批 client.insert('events', rows_data, column_names=['event_time','user_id','city'])
客户端实践 建议
连接池大小 按并发查询数设,别过大
并发查询 不超过 CPU 核数太多
写入 批量,单次 ≥1000 行
重试 对瞬时错误重试,对逻辑错误别重试
超时 设合理查询超时,防慢查询拖死

四、几个常见陷阱

陷阱一:高频小查询

有人把 ClickHouse 当 MySQL,每个用户请求都查一次,结果并发把集群拖垮。ClickHouse 不擅长高并发小查询,适合低频大查询。高频点查场景用 Redis 缓存兜底,ClickHouse 做后台聚合。

陷阱二:单行写入

# 错误:一行一写,灾难 for row in rows: client.insert('events', [row], ...)

单行写入制造海量小 part,合并跟不上。改成批量:

# 正确:批量写 client.insert('events', rows, ...)

陷阱三:SELECT *

应用查询用 SELECT * 读所有列,把列存优势废了。永远显式列清单,只读需要的列。

陷阱四:不设超时

没设查询超时,慢查询一直挂着占资源。客户端和服务器都要设超时。

⚠️ 常见坑:把 ClickHouse 当通用数据库用——高频小查询、单行写入、SELECT *、不设超时,这四样凑齐,再好的集群也扛不住。ClickHouse 有它的脾气,顺着它的脾气用才省心。

💡 关键直觉:选驱动看协议(有原生用原生,没原生用 HTTP),用驱动要配合 ClickHouse 的并发模型(少而精、批量写、显式列、设超时)。客户端侧的坏习惯比服务端配置更毁性能。

本章回顾

  • 两种协议:原生 TCP(9000,快)、HTTP(8123,通用),有原生驱动用原生。
  • 各语言:Java JDBC/clickhouse-client、Python clickhouse-connect/clickhouse-driver、Go clickhouse-go、Node @clickhouse/client。
  • 连接池:复用但别过大,并发查询数不超 CPU 核数太多。
  • 批量写入:单次 ≥1000 行,别单行写。
  • 四陷阱:高频小查询、单行写入、SELECT *、不设超时——避开这四样。
  • ClickHouse 有脾气,顺着用才省心。

最后一节把这些串成架构最佳实践,给你一个端到端的设计参考。

驱动选型与代码级实践

驱动的选择不只是"哪个库能用",还牵涉到数据格式、批处理、错误处理。Python 场景两个驱动各有定位,选型标准可以这样把握:

import clickhouse_connect # 分析场景:clickhouse-connect(HTTP,简单) client = clickhouse_connect.get_client(host='ch1', port=8123, user='analyst', password='pwd') result = client.query("SELECT city, count() FROM events GROUP BY city LIMIT 10") for row in result.result_rows: print(row)

高吞吐写入场景,用原生协议驱动(如 clickhouse-driver)并用批量写入接口,避免一行一次 insert。批量写入是 ClickHouse 客户端最重要的实践,没有之一:

import time import clickhouse_driver client = clickhouse_driver.Client(host='ch1') # 攒批:一次插 10000 行 rows = [(int(time.time()), user_id, city, amount) for user_id, city, amount in data] client.execute( 'INSERT INTO events (event_time, user_id, city, amount) VALUES', rows, types_check=True, # 开启类型检查,提前暴露类型不匹配 )

批量写入的两个额外注意点:一是 types_check=True 能帮你在开发期就发现类型错误,而不是上线后由服务端拒绝;二是写入超时要单独设,批量插入耗时可能超过查询超时。这两种情况都属于"客户端侧最常见的坑",提前配好比出事后排查省心。

Java 场景走 JDBC 时同理:用 HikariCP 做连接池,但连接池大小按并发查询数设(比如核数的一半),别盲目调大;写操作用 PreparedStatementaddBatch() 批量提交。驱动只是管道,顺着 ClickHouse"少而精、批量写"的脾气用它,性能才有保障。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U