You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SQLAlchemy连接ClickHouse遇UnexpectedPacketFromServerError求助

问题分析与解决方案

核心原因:协议不匹配

你遇到的asynch.errors.UnexpectedPacketFromServerError错误,本质是客户端使用的协议与目标端口的服务协议不兼容。

你用clickhouse+asynch:// URI时,底层是基于clickhouse-driver的原生TCP协议通信,但DataGrid能正常连接31123端口,说明这个端口对应的是ClickHouse的HTTP协议端口(默认是8123),而非原生TCP端口(默认是9000)。两种协议的数据包格式完全不同,因此会出现"未知数据包"的错误。

解决方案

方案1:切换到正确的TCP端口

确认你的ClickHouse服务的原生TCP端口(通常是9000,若修改过则对应实际端口),将URI中的端口替换为该TCP端口:

self.ch_uri: str = "clickhouse+asynch://admin:Password123@host:[TCP_PORT]/db"

方案2:改用HTTP协议连接(同步/异步适配)

如果必须使用31123端口(HTTP端口),则需要调整连接协议:

  • 同步场景:使用clickhouse+http:// URI:
    from sqlalchemy import create_engine
    engine = create_engine("clickhouse+http://admin:Password123@host:31123/db")
    
  • 异步场景:由于asynch库仅支持原生TCP协议,若要通过HTTP异步连接,可改用aiohttp配合ClickHouse的HTTP API,或者使用支持异步HTTP的SQLAlchemy适配器(如sqlalchemy-clickhouse-http,需自行安装)。

额外代码修复:Session管理错误

你的代码中存在Session复用的问题:初始化AsyncDatabase时创建了一个全局ch_session,但get_ch_session每次返回这个已创建的Session,关闭后该Session就会失效,后续无法再使用。正确的做法是在上下文管理器中每次创建新的Session:

@contextlib.asynccontextmanager
async def get_ch_session() -> typing.AsyncGenerator[AsyncSession, None]:
    # 每次请求创建新的Session
    session = AsyncSession(bind=async_db.ch_engine)
    try:
        yield session
        # 正常执行时提交
        await session.commit()
    except Exception as e:
        print(traceback.print_exc())
        await session.rollback()
    finally:
        await session.close()

验证步骤

  1. 先确认ClickHouse服务的端口映射:查看ClickHouse配置文件config.xml中的tcp_port(原生TCP)和http_port(HTTP)配置项。
  2. 根据端口对应的协议选择正确的URI格式。
  3. 修复Session管理逻辑,避免复用已关闭的Session。

内容的提问来源于stack exchange,提问作者Nguyễn Đức Huy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 08:23:30