上线之后怎么验收:延迟限流与异步索引
上篇博客讲了怎么把个人项目挂到公网浏览器能登录、能上传、能问答算是把主链路跑通了。这篇主要是讲上线后的工程质量验收护栏会不会拒、会不会误伤异步索引是不是真在跑慢的时候大概慢在哪。例子还是用我的开源项目 DocPaws在 2 核 2G 演示机上做一轮。先搞清请求怎么走再按两条链路验收问答侧准备脚本 → 验限流 → 抽延迟上传/索引侧上传 → ready → 改一处找瓶颈一、一台机上请求怎么走/api开流前上传文档浏览器NginxAPI限流每分钟次数 / 同时几路模型流式回答任务队列Celery worker向量 / 索引 ready问答限流在真正开 SSE 之前就拦拦不住才去调模型。上传接口很快返回真正建索引的是后台 worker页面变成 ready才算这条链路完成。为什么非要拦在开流之前因为一旦已经出字模型调用、连接占用都花出去了超配额的请求还可能已经拿到内容——护栏等于白装。拦在前面才是省成本、让限流真管用。DocPaws 里常见配置在后端.env含义配置名示例演示机常用值开不开限流CHAT_RATE_LIMIT_ENABLEDtrue每分钟最多问几次CHAT_RATE_LIMIT_PER_MINUTE日常20测拒绝时临时改5同时最多几路问答CHAT_CONCURRENT_LIMIT默认常2改完.env一定要重启 APIDocPaws 用 systemd 时sudo systemctl restart docpaws-api。二、问答侧验收限流与延迟这一侧共用同一套东西登录态 固定题 小脚本。先准备好再验限流、再抽延迟。1. 准备浏览器走通登录 → 小 PDF 索引ready→ 能流式问答。开发者工具里抄三样Cookie 里的session登录态知识库kb_id一道固定问题为了做这轮验收我让 AI 写了个小脚本仓库里在eval/bench_chat_stream.py对同一道题反复打问答接口记首包多久开始出字和整段耗时多久答完撞上限流就拿 HTTP 429Too Many Requests表示「你问太勤被拒了」。用--mode切换几种验收场景就行——baseline抽延迟burst/pace验限流拒与不误杀verify改回日常频率后再确认。2. 验限流该拒则拒正常节奏不误杀为什么先验限流它像小区门禁太松闲杂人员随便进模型调用费可能被刷太紧业主自己也被挡在外面。所以要验两件事——它们其实是同一个机制的两个相反失败方向拒绝防漏问太勤该拦下来常见是 HTTP 429。漏了护栏等于没装。误杀防滥按正常人的节奏问不该被拦。滥了用户用不了这肯定也不行。临时把「每分钟次数」调严编辑后端.env例如改成每分钟只允许 5 次然后重启 APIsudosystemctl restart docpaws-api狂打看会不会拒本机python3 bench_chat_stream.py--modeburst我在演示机上的结果频率5连打 18 次前5次成功后面13次 429。说明超配额会被拦——护栏是活的。然后仍保持频率5但每次隔十几秒再问python3 bench_chat_stream.py--modepace我这边 8 次全成功、0 次 429。说明节奏已经低于配额时不会误伤。改回日常频率再验一遍把.env改回例如20重启 API再跑python3 bench_chat_stream.py--modeverify几乎没有 429。场景频率结果我的演示机狂打518 次里 13 次 429慢打58 次全过误杀 0改回后再验2010 次全过3. 抽一轮问答延迟限流验完、频率回到日常后再抽一轮体感基线——以后变慢了才知道相对什么变了python3 bench_chat_stream.py--modebaseline脚本串行问二三十次打出首包和整段的分位。首包TTFT多久出现第一条data:感觉开始出字。整段(E2E)多久答完大头多半在模型生成。次数不多看 P50 量级即可别当 SLA串行也说明不了多人同时问会怎样。在测试时我发现前二十几次还正常到大约第 24 次附近脚本报 HTTP 500系统繁忙。这和限流 429 不是一类事429 是护栏在拦这里是池子里借不到连接了。API 日志里能看到类似sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30.00后面发现是问答路径把数据库连接握太久、没还干净——旧实现往往借一次就握到答完等模型吐字也占着名额。串行都能打满说明不是测太狠是资源生命周期有问题。后来把后端改成短借短还才能正常测完。我这轮测的数据25 次全过、无 429首包中位约 42ms整段中位约 11s。三、上传/索引侧验收1. 上传 → ready为什么单独验这一条上传接口返回「成功」和文档变成ready不是一回事——中间靠后台 worker。文件一直显示传输中往往是异步链路没起来或任务挂了。SSH 确认 worker 在跑上传前就挂上日志sudosystemctl status docpaws-workersudojournalctl-udocpaws-worker-f浏览器传一个不用太大的 PDF大约 12MB 就够了。看两样页面/状态何时变成ready日志里是否出现任务received→ 切块 / 向量 →succeeded。可选再开一个窗口用htop瞄一眼内存 CPU。我在 2C2G 上、约 2MB 样例任务大约0.40.9 秒就成功机器 Load 很低、内存大概用到 1G/1.57G 量级没有明显积压。2. 改一处再比找瓶颈只改一个配置项、同一路径前后对比才能把快慢钉到具体原因上。我把 Celery--concurrency同时能并行啃几条任务从默认调到 4再传差不多的小 PDF规模chunks改前改后约 11≈0.98s≈0.75s基本持平。一次只传一个文件时加 worker 数往往缩短不了这一单时间主要花在切块和 embedding文本转向量上。从而结论瓶颈不在 concurrency而在任务内 / 外部向量接口。四、进阶做法可选同时开几路问答并发租约「租约」可以理解成开一路问答就占一个名额答完或超时再还回来。DocPaws 除了「每分钟次数」还有「同时最多几路」。默认常常是 2。同一账号同时开 3 路应有人拿到 429错误码里常见是CONCURRENT_LIMITED「同时开太多路」和分钟桶的RATE_LIMITED「这一分钟问太勤」不同。三路都结束后马上再问一次应能通过——说明名额有释放。若只有「等很久再试」才恢复那测的是过期兜底不是「结束就释放」。两件事别混。Redis 挂了会怎样Redis 在这里常被限流拿来记「你已经问了几次 / 占了几路」。短停 Redis 再问理想是明确失败例如服务暂不可用而不是限流悄悄失效、人人狂打。