Go Worker 池:限制并发不是保守,是保护下游

📅 2026/7/3 1:44:11
Go Worker 池:限制并发不是保守,是保护下游
Go Worker 池限制并发不是保守是保护下游Go 写 worker 很容易起很多 goroutine。语言层面很轻写起来也顺手。但生产服务里并发不是越多越好。AI 后端常常依赖模型网关、数据库、向量库和对象存储worker 不限制并发会把下游打满。Worker 池的价值是把吞吐控制在系统能承受的范围内。限制并发不是保守而是保护下游。一、先明确并发预算并发预算来自下游能力而不是 CPU 核数。比如模型网关允许每租户 20 个并发向量库建议 50 个查询并发数据库连接池只有 30。Worker 池要服从这些边界。flowchart TD A[任务队列] -- B[Worker 池] B -- C[模型网关] B -- D[数据库] B -- E[对象存储] C -- F[下游容量约束] D -- F E -- F如果只看本服务 CPU扩到 200 个 goroutine很可能把数据库先打挂。二、用 channel 控制并发一个简单 worker 池如下func RunWorkers(ctx context.Context, jobs -chan Job, n int) { var wg sync.WaitGroup for i : 0; i n; i { wg.Add(1) go func() { defer wg.Done() for { select { case -ctx.Done(): return case job, ok : -jobs: if !ok { return } process(ctx, job) } } }() } wg.Wait() }这段代码的重点不是技巧而是可控。worker 数量明确退出路径明确队列关闭后能结束。三、每个任务都要有超时没有超时的 worker 会被慢请求占住。AI 调用、网络请求、文件上传都要带 context timeout。func process(parent context.Context, job Job) { ctx, cancel : context.WithTimeout(parent, 60*time.Second) defer cancel() _ callDownstream(ctx, job) }超时后要记录任务状态决定重试还是失败。不能让 goroutine 悄悄卡住。四、指标要看运行中和等待中Worker 池至少记录 running、pending、success、failed、timeout 和处理耗时。只看成功数会漏掉等待和超时。当 pending 增长而 running 达到上限说明需要扩 worker 或降级当 running 不满但 pending 高可能是拉取逻辑有问题当 timeout 增长要看下游。五、总结Go Worker 池的核心是并发预算。根据下游能力限制 worker 数每个任务有超时退出路径清楚指标覆盖运行和等待。生产服务里能起多少 goroutine 不重要系统能稳定承受多少并发才重要。