clickhouse-driver 是纯同步客户端,不支持真正异步;需改用 aioclickhouse 或 httpx.asyncclient 调用 http 接口,并注意连接池、wait_end_of_query、ssl 配置及服务端并发限制。

clickhouse-driver 本身不支持异步
它是个纯同步的 Python 客户端,底层用 http.client 或 socket 实现,所有方法(比如 execute()、fetchall())都会阻塞当前线程。你用 async def 包裹它,或者扔进 asyncio.to_thread(),只是“模拟”异步,并不能提升并发吞吐——IO 还是串行等响应。
想真正异步,得换库:aioclickhouse 或 httpx + 手写
aioclickhouse 是目前最接近开箱即用的异步方案,基于 aiohttp,支持连接池、prepared statement 和基本类型映射。但它维护不活跃,最新 release 停在 2022 年,对 ClickHouse 新版协议(如 compression、ssl 配置)支持有限。
更稳妥的做法是绕过驱动,直接用 httpx.AsyncClient 调 ClickHouse 的 HTTP 接口:
-
httpx.AsyncClient支持连接复用、超时控制、自动解压,比手写aiohttp更省心 - 所有查询走
POST /?database=xxx,SQL 体放在 request body,返回是 TSV/JSONEachRow,需自行解析 - 注意设置
Content-Type: application/x-www-form-urlencoded或text/plain,否则 400 - 批量插入时别拼大字符串,用
httpx.stream流式上传,避免内存暴涨
asyncio.to_thread 是临时解法,但有隐藏成本
如果你只是想把老代码快速包一层 async,asyncio.to_thread() 确实能跑通,但要注意:
立即学习“Python免费学习笔记(深入)”;
- 每个查询都新建一个线程,高并发下线程数爆炸,容易触发
OSError: can't start new thread - ClickHouse 默认单查询超时是 300 秒,线程卡住就一直占着,没超时熔断机制
-
clickhouse-driver的Client实例不是线程安全的,多线程共用同一实例可能引发AttributeError或数据错乱 - 如果用了
compression=True,解压过程 CPU 密集,反而拖慢 event loop
连接池和超时必须手动管,没有默认值
无论是 aioclickhouse 还是 httpx.AsyncClient,都不像 clickhouse-driver 那样帮你兜底。常见疏漏点:
-
httpx.AsyncClient默认不启用连接池,要显式传limits=httpx.Limits(max_connections=20) - ClickHouse 的
wait_end_of_query=1参数必须加在 URL query string 里,否则异步请求可能返回 200 却没数据 - 服务端
max_concurrent_queries限制常被忽略,客户端并发 > 100 时,大量请求会卡在排队状态,表现为“无错误但极慢” - SSL 验证默认开启,自签名证书环境要加
verify=False,但生产环境务必配好 CA bundle 路径
异步不是加个 async 就完事,ClickHouse 的查询生命周期、服务端资源水位、HTTP 协议细节,哪一环松动都会让整个链路卡住。尤其注意 wait_end_of_query 和连接池大小这两个参数,线上出问题八成栽在这儿。










