故障排查
一份症状、原因和修复方法的参考,涵盖课程构建和测试过程中出现过的每一个故障,并按出现位置分组。
下面的每一条都是课程构建和测试过程中真实发生过的故障。找到你的症状,读懂原因,套用修复 方法。如果这里没有匹配的内容,就把问题交给你的编码助手, 自主学习指南 里有一段可直接粘贴的提示词,能把它变成你的讲师。
Windows 与 WSL 2
wsl --install 不可用或只打印帮助信息
- 症状:管理员 PowerShell 不识别
wsl --install,或者它打印帮助信息而不是安装 Ubuntu。 - 原因:Windows 低于本课程的最低要求、待安装的更新尚未应用,或者公司策略禁用了 WSL。
- 修复:运行 Windows Update,并确认系统是 Windows 11 或 Windows 10 版本 2004 (build 19041)及更高版本。重启,然后按照 Microsoft 的 WSL 手动安装步骤 操作。 在受管控的机器上,需要管理员放开所需的 Windows 功能。
某条命令在 PowerShell 中「无法识别」
-
症状:PowerShell 拒绝执行课程提供的
./preflight.sh、export、source或其他 Bash 命令。 -
原因:Windows 的环境准备只在明确标注的 WSL 引导环节使用 PowerShell。 实训命令都在 WSL 2 上的 Ubuntu 里运行。
-
修复:从开始菜单打开 Ubuntu,然后回到应用目录并在那里运行 preflight:
cd ~/ClickHouse_Demos/workshops/build_workshop/app ./preflight.sh
仓库位于 /mnt/c 下
-
症状:Docker 的 bind mount 很慢、脚本出现权限或行尾符相关的故障,或者仓库路径以
/mnt/c/Users/...开头。 -
原因:仓库被克隆到了 Windows 文件系统上,而不是 WSL 的 Linux 文件系统。
-
修复:只有在你需要保留未提交的工作时才留着旧副本。否则,打开 Ubuntu 并在你的 Linux 主目录中克隆一份干净的副本:
cd ~ git config --global core.autocrlf input git clone https://github.com/ClickHouse/ClickHouse_Demos.git cd ClickHouse_Demos git switch build-workshop-v1 cd workshops/build_workshop/app cp .env.workshop.example .env.workshop
Ubuntu 以 WSL 1 方式运行
-
症状:
wsl --list --verbose显示 Ubuntu 的VERSION 1,或者 Docker Desktop 无法与该发行版集成。 -
原因:这个发行版早于 WSL 2,或者安装时默认使用了 WSL 1。
-
修复:以 管理员身份打开 PowerShell,转换它,然后重新打开 Ubuntu:
wsl --set-version Ubuntu 2 wsl --set-default-version 2 wsl --list --verbose
在 Ubuntu 内 docker 不可用
- 症状:Docker Desktop 正在运行,但 Ubuntu 提示
docker: command not found或者 连不上守护进程。 - 原因:Docker Desktop 的 WSL 引擎或 Ubuntu 集成被禁用了。
- 修复:启用 Docker Desktop -> Settings -> General -> Use the WSL 2 based engine
和 Resources -> WSL Integration -> Ubuntu,应用改动,然后在 PowerShell 中运行
wsl --shutdown并重新打开 Ubuntu。之后docker version必须同时显示 Client 和 Server 两部分。
WSL 或 Docker 的内存不足 6 GB
-
症状:preflight 报告内存不足,或者
docker info --format 'Docker memory: {{.MemTotal}} bytes'打印出小于6442450944字节的值。 -
原因:Docker Desktop 的 WSL 2 后端使用的是 WSL 虚拟机的内存上限。
-
修复:关闭 Docker Desktop,打开 PowerShell,并创建一个 8 GB 的 WSL 上限:
@('[wsl2]', 'memory=8GB', 'processors=4') | Set-Content -Encoding ascii "$env:USERPROFILE\.wslconfig" wsl --shutdown启动 Docker Desktop 并重新打开 Ubuntu。重新运行那条
docker info命令和 preflight。
某个脚本报告 /usr/bin/env: 'bash\r': No such file or directory
-
症状:某个
.sh文件立即失败,错误信息中包含bash\r或^M。 -
原因:Windows 的 CRLF 行尾符替换了仓库要求的 LF 行尾符。
-
修复:在 Ubuntu 中设置 Git 的 WSL 策略,并恢复一份干净的检出:
git config --global core.autocrlf input git status --short git add --renormalize .在丢弃或提交任何东西之前,先检查
git status。如果这份检出里没有你需要的工作, 在~/ClickHouse_Demos下重新克隆一份干净副本是最安全的恢复方式。
OAuth 没有打开 Windows 浏览器
- 症状:MCP 登录打印出一个 URL,但没有浏览器窗口打开。
- 原因:编码助手运行在 WSL 内部,而浏览器转发不可用或被公司策略阻止。
- 修复:从 Ubuntu 中复制完整的登录 URL,粘贴到普通的 Windows 浏览器里。 在那里完成授权,然后回到 Ubuntu 终端。
Docker
容器卡在 "Created" 状态从不启动
- 症状:
docker info响应正常,但docker compose ... up让容器停留在Created状态,且从来没有任何容器变为 healthy。 - 原因:Docker 引擎卡死了:守护进程有响应,但它实际上无法启动容器。曾在一次现场启动中 于 OrbStack 上出现过。
- 修复:重启你的 Docker 引擎(Docker Desktop、OrbStack 或 Colima),等到它报告
Running,然后再次启动这套技术栈。在克隆仓库内的任何位置运行
cd "$(git rev-parse --show-toplevel)/workshops/build_workshop/app" && ./preflight.sh; 它会通过运行一个一次性容器作为测试,在你启动技术栈之前就捕获这个问题。
启动时出现 "port is already allocated"
- 症状:
docker compose ... up失败,提示Bind for 0.0.0.0:8080 failed: port is already allocated(或:8000)。 - 原因:另一个进程,或者一个旧的实训容器,已经占用了那个宿主机端口。
- 修复:在克隆仓库内的任何位置运行
cd "$(git rev-parse --show-toplevel)/workshops/build_workshop/app" && ./preflight.sh。 它会指出是什么占用了端口,并按照「基础端口 + 20000」的约定打印出确切的覆盖设置,例如set FRONTEND_HOST_PORT=28080 in .env.workshop。可用的覆盖变量是FRONTEND_HOST_PORT、BACKEND_HOST_PORT,以及用于可观测性 overlay 的OTEL_GRPC_HOST_PORT/OTEL_HTTP_HOST_PORT。设置建议的值、重新运行 preflight,然后启动技术栈。只有宿主机端口发生了变化;容器内的端口不变,所以这是安全的。
"platform does not match" 告警
- 症状:Docker 在 pull 或 up 时打印平台不匹配告警(例如
linux/amd64对linux/arm64)。 - 原因:某个镜像是为与你的机器不同的 CPU 架构构建的,这在 Apple Silicon 上很常见。
- 修复:无害。这是告警而不是失败;镜像会在模拟下运行。让它继续即可。
ClickHouse Cloud
空闲之后的第一个请求很慢,或偶尔返回一次 500
- 症状:服务空闲之后的第一个查询或看板加载很慢,或者某个请求返回一次 500 然后就正常了。
- 原因:Cloud 服务会空闲缩容到零,唤醒需要约 30 秒;第一个请求要承担这个唤醒开销。 后端已经为首次连接设置了更长的超时,并会重试一次。
- 修复:直接重试,或者等约 30 秒。这不是故障。这一点在 07 测试、失败与修复 中也很重要: 一个正在唤醒的服务会让故障 03 的超时更容易触发。
服务密码丢了
- 症状:你没有保存
default用户的密码,现在找不到它了。 - 原因:离开创建流程之后,服务密码不会再次显示。
- 修复:打开该服务,进入它的 Settings 并重置
default用户的密码, 然后更新.env.workshop中的CLICKHOUSE_PASSWORD。主机名随时可以从 Connect 弹窗中获取。
托管 Postgres 的密码丢了
- 症状:你没有保存
clickhousectl cloud postgres create给出的一次性postgres管理员密码。 - 原因:它只显示一次,而且处于 beta 阶段的
postgres get/listAPI 即使在实例 健康时也可能返回空结果或 FORBIDDEN。 - 修复:执行
clickhousectl cloud postgres reset-password <service-id>,然后在.env.workshop(PGPASSWORD)和 ClickPipe 连接中使用新密码。
ClickHouse Cloud 无法访问
-
症状:preflight 的连通性检查 FAIL,或者后端连不上; the command below 失败。
CLICKHOUSE_HOST=$(sed -n 's/^CLICKHOUSE_HOST=//p' .env.workshop | tail -n 1) CLICKHOUSE_PORT=$(sed -n 's/^CLICKHOUSE_PORT=//p' .env.workshop | tail -n 1) curl "https://$CLICKHOUSE_HOST:$CLICKHOUSE_PORT/ping" -
原因:wifi、VPN 或防火墙;主机名错误(把协议前缀或端口粘进了
CLICKHOUSE_HOST);TLS 或端口不匹配;或者 Cloud 的 IP 访问列表阻止了你的 IP。 -
修复:确认
CLICKHOUSE_HOST是纯主机名(不带https://,不带端口)、CLICKHOUSE_PORT=8443、CLICKHOUSE_SECURE=true;检查 VPN 和防火墙;确认该 服务的 IP 访问列表允许你的地址。preflight 会指出具体的失败类型,DNS、 连接被拒、超时或 TLS 握手。
客户端打印 Unknown settings: ... skipping
- 症状:查询能成功,但每次调用都会打印一条未知设置的告警。
- 原因:本地安装的客户端比 Cloud 服务端更新,发送了该服务端版本不认识的设置项。
- 修复:重做模块 00 第 6 步中匹配客户端版本的那几条命令。它们会通过
clickhousectl读取 Cloud 服务端的版本,并选择对应的主/次版本客户端 发行版。不要用--no-warnings把所有客户端告警都隐藏掉。
CDC(模块 03)
创建 ClickPipe 时提示 table realtime_trips exists and is not empty
-
症状:并不存在任何 ClickPipe 资源,但重新创建它却失败了,因为
default.realtime_trips中已经有数据行。 -
原因:删除一个 ClickPipe 会移除它在源端的复制槽,但可能会把目标表留下来。 新的 pipe 不会覆盖那张非空的表。
-
修复:用带时间戳的备份名保留旧的原始数据行,然后重新创建这个 pipe。只需替换一次服务 ID 占位符;下面这些命令在旧的 materialized view 存在时 也会把它保留下来:
CH_SERVICE_ID=<clickhouse-service-id> BACKUP_SUFFIX=$(date -u +%Y%m%d%H%M%S) if clickhousectl cloud service query --id "$CH_SERVICE_ID" \ --query "EXISTS TABLE nyc_tlc_data.realtime_trips_to_taxi_trips_mv" | grep -q 1; then clickhousectl cloud service query --id "$CH_SERVICE_ID" --query " RENAME TABLE nyc_tlc_data.realtime_trips_to_taxi_trips_mv TO nyc_tlc_data.realtime_trips_to_taxi_trips_mv_backup_${BACKUP_SUFFIX} " fi clickhousectl cloud service query --id "$CH_SERVICE_ID" --query " RENAME TABLE default.realtime_trips TO default.realtime_trips_backup_${BACKUP_SUFFIX} "重新执行模块 03 的第 3 步,等新的
default.realtime_trips表出现之后, 再在第 4 步中重新创建标准的 materialized view。只有在你确认不再需要这些备份中的数据之后, 才在之后删除那些带时间戳的备份。
ClickPipe 卡在 "Provisioning"
- 症状:你创建 pipe 之后,它有一段时间一直显示 Provisioning。
- 原因:快照和基础设施启动通常要几分钟,但即使对这张小表,也可能超过 10 分钟。
- 修复:在控制台中查看进度,或者同时使用
clickhousectl cloud clickpipe list <clickhouse-service-id>和clickhousectl cloud clickpipe get <clickhouse-service-id> <clickpipe-id>。在最初的 几分钟里,只要它的状态或updatedAt值在往前推进,就继续等待。如果 10 分钟后它 仍然是 Provisioning 且没有任何更新,请确认pg-trip-writer日志 仍在插入数据,重新检查主机名、凭据、publication 和表映射,并 查看 pipe 报告的错误。在第一个 pipe 还在 provisioning 时,不要创建第二个 pipe 或者 materialized view。如果源端检查都通过、并且 Cloud 没有报告可处理的错误,请保存get的 输出,并升级给讲师或 ClickHouse Cloud 支持团队。
数据行没有到达 ClickHouse
- 症状:pipe 处于 Running,但目标表的行数没有增长,Ops 看板也没有变化。
- 原因:默认的同步间隔约为 60 秒,所以有延迟是正常的;或者生成器没有在插入数据; 或者 pipe 要读取的 publication 不存在。
- 修复:至少等 60 秒。检查
pg-trip-writer日志中出现了inserted N trips,以及created publication pub_taxi(你自己的实例)或publication ... already exists(讲师提供的托管兜底实例)。确认 pipe 状态为 Running。如果 publication 不存在,pipe 就没有任何东西可读,在你拥有管理员权限的实例上,生成器会在首次运行时 创建它。
Materialized view 中没有数据行
-
症状:
realtime_trips在增长,但(由 CDC materialized view 供给的)taxi_trips一直是空的。 -
原因:这个 materialized view 是在 ClickPipe 目标表存在之前创建的,或者它读取的 不是位于
default.realtime_trips的 CLI 目标表。 -
修复:等目标表出现,然后从 模块 03 第 4 步 复制完整的 materialized view 命令。先验证源表:
clickhousectl cloud service query --id <clickhouse-service-id> --query " SELECT database, name, engine FROM system.tables WHERE name = 'realtime_trips' "materialized view 只处理它存在之后插入的数据行;创建之后请让行程写入器继续运行。
复制槽停滞
- 症状:pipe 停滞,源 Postgres 上的 WAL 不断增长。
- 原因:停滞的复制槽会保留 WAL;重新同步会创建一个新的复制槽。
- 修复:在你自己的托管 Postgres 上(只有一个复制槽、余量充足),从控制台重新同步这个
pipe 即可。删除一个 pipe 会在源端删掉它的复制槽。任何由讲师提供的托管兜底资源池
属于讲师侧的事情,参见
infra/README.md。
环境变量
shell 中的 export 覆盖了 .env.workshop
- 症状:你在
.env.workshop中设置了一个值,但容器用的却是另一个值 (常见的是过期的OPENAI_API_KEY、某个LANGFUSE_*,或CLICKHOUSE_PASSWORD)。 - 原因:
docker compose会先从你的 shell 插值${VAR},而已导出的 shell 变量会「胜出」,压过文件里的值。 - 修复:在你运行 compose 的那个 shell 里执行
unset OPENAI_API_KEY LANGFUSE_PUBLIC_KEY LANGFUSE_SECRET_KEY LANGFUSE_BASE_URL CLICKHOUSE_PASSWORD, 然后重新启动这套技术栈。preflight 检测到这种情况时会发出告警。
.env.workshop 中有重复的键
- 症状:你在文件中设置的某个值被忽略了。
- 原因:同一个键出现了两次;最后一次出现的胜出,这与
docker compose的语义一致(preflight 也按同样方式读取它)。 - 修复:删掉靠前的那个重复项,只留下你想要的那个值。
聊天(模块 08)
POST /api/chat 返回 503 并附带一条配置提示
- 症状:聊天面板显示一条配置提示,
/api/chat返回 503;应用的其他部分都正常。 - 原因:后端没有设置
OPENAI_API_KEY。 - 修复:把
OPENAI_API_KEY加进.env.workshop,然后执行docker compose --env-file .env.workshop -f docker-compose.workshop.yml -f docker-compose.otel.yml up -d --build backend。 聊天是唯一需要它的功能。
无法创建第一个 OpenAI key
- 症状:OpenAI 不给新账号发放 API key。
- 原因:新账号需要一次性的手机验证,而且没有免费额度。
- 修复:完成手机验证,然后进入 Settings -> Billing:添加一种支付方式 并购买最低 5 美元 的预付额度。关闭自动充值(在设置过程中它默认是打开的), 这样你就绝不会被扣超过你充入的那 5 美元。
MCP 与 OAuth(模块 00 和 06)
MCP 端点返回 401
-
症状:访问
https://mcp.clickhouse.cloud/mcp(或/clickstack)返回 401。 -
原因:在你完成浏览器 OAuth 流程之前,这是预期行为;该端点需要认证。
-
修复:把这个服务器添加到你的 agent,然后运行 OAuth 流程并在浏览器中授权, 使用你所用工具对应的命令:
- Claude Code:运行
/mcp,选择该服务器并授权(或者claude mcp login <name>)。 - Codex CLI:运行
codex mcp login <name>。 - Cursor:打开 MCP 设置面板,点击该服务器的授权/登录控件。
同时确认你的服务已打开 Connect with MCP 开关。
- Claude Code:运行
公司笔记本阻止了 MCP 或 OAuth
- 症状:你的 agent 无法添加 MCP 服务器,或者 OAuth 重定向被阻止。
- 原因:受管控笔记本的策略阻止添加 MCP 服务器或对外的 OAuth。
- 修复:用个人电脑是最快的兜底方案。
Windsurf 无法通过原生 HTTP 连接
- 症状:Windsurf 连不上 MCP 端点,或者它的 OAuth 不稳定。
- 原因:Windsurf 是通过
mcp-remote连接的,而不是原生的 streamable HTTP。 - 修复:使用
mcp-remote的命令形式:{ "command": "npx", "args": ["-y", "mcp-remote", "https://mcp.clickhouse.cloud/mcp"] }(在模块 06 中接入 ClickStack MCP 时,把/mcp换成/clickstack)。