2026-07-02 · 目标机
.sessions.db 从 4.4G+4.5G WAL → 26M。GET /api/config/models:TCP connect 1.4ms,TTFB 4.5~9s——延迟全在服务端排队connect_sqlite 29.1%、TokenizerClient.__init__ 20.2%、投影 on_event 8.9%、agent_board _connection 6.5%、next_sequence 3.8%;栈上 _maybe_emit_agent_board_file_op 33.7%、_build_compactor 21.1%bg-stream docker 流读取线程,随后台任务线性增长)_connection 30% + connect_sqlite 26.1% + next_sequence 13%;52.9% 样本在 starlette 请求栈内——async REST 路由在事件循环上直接做同步 SQLitepayload_log 从热点消失——但它从来不是主热点bridge._maybe_emit_agent_board_file_op → get_by_session(47.2%) → 每次新开 SQLite 连接(46.5%)。触发源是 llm:tool_call:created——流式 tool call 的每个参数 delta 都查一次库,且代码是"先查库、后判断事件类型"projections.builder.on_event 叶子帧 29.4%(栈上 42.2%)成为最大单点——每个流式 delta 的纯 Python 计算host/llm/client.py:590 每次流式请求新建 httpx.AsyncClient——每请求重建 SSL context(ssl.create_default_context 叶子帧 2.4%)、重新 TLS 握手、零连接复用| 指标 | 最差时(第二轮) | 修复部署后(第四轮) | 高并发压测(第五轮) |
|---|---|---|---|
| 轻量接口 TTFB | 40.7s | 0.5~1.9s | 4~6s |
| 主线程 SQLite 占比 | ~70% | ~9% | ~12% |
| fdatasync 频率 | ≈380 次/秒 | 正常(synchronous=NORMAL 后仅 checkpoint 刷盘) | |
| 宿主机 load(32 核) | 4.75 | 1.9 | 2.5 |
| .sessions.db 体积 | 4.4G + 4.5G WAL | 26M + 0 WAL | |
blade-agent 是有状态单进程(Engine 内存态 + Socket.IO in-process),无法横向加 uvicorn worker,所以事件循环主线程就是全局串行点。任何同步阻塞都会让所有用户一起排队。本次按占比从大到小依次挖出:
bridge._maybe_emit_agent_board_file_op 先查 agent-board 归属、后判断事件类型;配合 store 每次 connect+pragma+close。智能体流式写文件时每个参数分片都要走一遍。(#1135 连接复用 + #1138 事件过滤/缓存)synchronous=FULL,380 次/秒刷盘把事件循环钉在磁盘上。(#1134)/opt/box-deploy/workspace/.sessions.db(全业务共享库:users / sessions / agent_board 等 40+ 张表都在里面),23894 行占了 4.4G 的 99.4%DELETE FROM llm_payloads 耗时 32s;但 wal_checkpoint(TRUNCATE) 被 box-ba 内一个长期不结束的读事务钉住(反复重试都卡在同一帧位),WAL 反涨到 4.5GVACUUM 实际 0.1s → 再 checkpoint 截断这是 Blade 盒子离线交付的预期设计,不是配置错误。链路:/opt/box-deploy/.env 的 SANDBOX_PIP_INDEX_URL / SANDBOX_NPM_CONFIG_REGISTRY → compose 传给 box-ba → blade-agent 创建沙盒时注入 PIP_INDEX_URL / NPM_CONFIG_REGISTRY 环境变量(sandbox/docker_utils.py)。30020 是 box-nexus-index(自研前置索引),背后是 Sonatype Nexus 的 pypi-proxy / npm-proxy 代理仓库:断网时命中预热缓存,有网时代理上游并缓存,几十个沙盒的下载流量收敛到本机。环境变量优先级高于 .npmrc,所以沙盒里写的 npmmirror 不生效。
延迟归因:curl -w "connect=%{time_connect} ttfb=%{time_starttransfer}" —— connect 快 + TTFB 慢 = 服务端排队,与网络无关。
Python 热点:宿主机装 py-spy 直接 attach 容器内进程 PID(pip3 install py-spy --user --break-system-packages),record -f speedscope 采样后按主线程聚合叶子帧(self time)与栈上占比(total time)。采样文件留存于 b212 /tmp/,可拖入 speedscope.app 看火焰图。
syscall 佐证:timeout 8 strace -c -f -p PID —— futex 占比看 GIL/锁竞争,fdatasync/openat/fcntl 频次看 SQLite 行为模式。
SQLite 空间:PRAGMA page_count / freelist_count 先估活数据量再决定 VACUUM;checkpoint 返回 busy|log|checkpointed 三元组判断是否被读事务阻塞。