跨层并发治理总览#
涉及: Layer 1 (API 接入) · Layer 2 (队列缓冲) · Layer 3 (编排调度)
并发治理不是某一层的事。V3 把”接收请求、排队任务、执行诊断”拆成三件不同的事,每一层用不同手段削峰限流,避免所有压力都挤到 Agent 执行阶段。
压力来源拆解#
AIOps 系统里的”压力”不是一种压力,而是多条链路同时受压。V3 把它们分开处理:
| 压力来源 | 典型场景 | 风险 | 治理层级 | 处理方式 |
|---|---|---|---|---|
| 用户请求压力 | 多人同时点击诊断 | API 线程被长任务占住 | Layer 1 | 同步/异步分流,高并发走后台提交 |
| 告警洪峰压力 | Alertmanager 批量推送 firing | 告警入口阻塞,任务重复 | Layer 1 | Webhook 只做校验、归一、去重、入库、入队 |
| 队列堆积压力 | 短时间提交多于消费能力 | 任务越积越多 | Layer 2 | 队列保存 backlog,前端展示位置/深度/lag/DLQ |
| Worker 执行压力 | 多 Worker 同时跑 Agent | LLM/RAG/MCP 被并发打满 | Layer 3 | 所有 Worker 共享全局执行上限 |
| LLM 成本/配额压力 | 多任务同时规划、执行、生成报告 | token 成本失控,RPM/TPM 打满 | Layer 3+4 | prompt 收敛、模型分层、步骤上限、token 统计 |
| RAG/向量库压力 | 多诊断同时检索、rerank | 延迟升高 | Layer 3 | 后台执行限额间接保护检索链路 |
| MCP 工具压力 | 多诊断同时查系统/网络/Docker | 外部依赖抖动 | Layer 4+6 | Skill 工具白名单、并行上限、失败降级 |
| 数据库写入压力 | 大量任务/证据同时落库 | 连接池耗尽 | Layer 7 | 任务状态分阶段写入,Redis 只保存运行态 |
| 前端长连接压力 | 多个 SSE 同时流式输出 | 连接占用时间长 | Layer 1 | 同步 SSE 适合少量即时诊断,批量走后台 |
六层治理体系#
每一层解决一个不同的问题,自上而下逐级收敛:
并发请求数 (可以很大)
│
┌─ 1. 接入层削峰 ──────────────┤ Layer 1
│ API 只做校验、落库、入队 │
│ 立即返回 task_id │
└──────────────────────────────┤
│
┌─ 2. 队列缓冲 ────────────────┤ Layer 2
│ Redis Streams 四级优先级 │
│ critical > high > normal > low
└──────────────────────────────┤
│ 排队任务数 (按需积压)
│
┌─ 3. 执行层限额 ──────────────┤ Layer 3
│ 全局 Redis ZSET 执行槽 │
│ 3 Worker 共享 2 个真实执行名额 │
└──────────────────────────────┤
│ 真实诊断并发 (严格可控)
│
┌─ 4. 接口限流 ────────────────┤ Layer 1
│ 固定窗口 + Redis INCR │
│ 手动 20/min/IP, Webhook 500/min/receiver
└──────────────────────────────┤
│
┌─ 5. 失败恢复 ────────────────┤ Layer 2+3
│ XAUTOCLAIM 回收 stale 任务 │
│ 重试 + 死信队列 │
└──────────────────────────────┤
│
┌─ 6. 可观测闭环 ──────────────┤ Layer 1+2+3
│ 队列深度/pending/lag/DLQ │
│ Worker 存活/执行槽占用 │
└──────────────────────────────┘plaintext关键点:并发请求数量、排队任务数量、真实诊断执行数量是三件不同的事。V3 允许短时间接收更多请求,但把昂贵的诊断执行收敛到一个可控上限内。
各层治理详解#
| 层级 | 解决的问题 | 做法 | 详见 |
|---|---|---|---|
| 接入层削峰 | 请求和告警不能直接压到 Agent | API 只做校验、落库、入队,立即返回 task_id | 01-api-layer.md §1.1-1.2 |
| 队列缓冲 | 短时间大量任务需要排队 | 四级优先级队列,高优告警先被 Worker 领取 | 02-queue-layer.md §2.1-2.2 |
| 执行层限额 | Worker 可扩展,但 LLM/RAG/MCP 有配额 | 所有 Worker 共享全局执行上限 (Redis ZSET + Lua) | 03-orchestration-layer.md §3.2 |
| 接口限流 | 防止单用户/IP/告警源刷爆系统 | 固定窗口计数器,超限返回 429 | 01-api-layer.md §1.3 |
| 失败恢复 | Worker 崩溃或任务超时不能丢任务 | XAUTOCLAIM 回收 + 重试 + DLQ | 02-queue-layer.md §2.4 |
| 可观测闭环 | 并发治理必须能被看见 | 队列深度/pending/lag/DLQ/Worker 存活/执行槽占用 | 02-queue-layer.md §2.6 |
与压测报告的关系#
本文描述设计意图,实测数据见 PRESSURE_TEST_REPORT.md。压测验证了:
- 读接口 3000 请求 / 200 并发,100% 成功
- 后台诊断提交 200 请求 / 100 并发,100% 入队
- Webhook 500 请求 / 100 并发,告警全部接收、归一、落库
- 全局执行槽始终不超过 2/2,真实诊断并发可控
模拟面试问答#
🔥 热点拷问#
面试官:你这个并发设计,本地跑 3 个 Worker、2 个执行槽,跟生产环境差距大不大?你怎么证明这套东西上了生产能用?
差距肯定有。本地压测验证的是机制正确性——队列削峰、执行槽限制、优先级抢占、DLQ 这些逻辑在并发下是否按预期工作。生产环境的变量更多:网络延迟、Redis/Postgres 集群化、LLM API 的 RPM 波动。当前配置(3 Worker / 2 槽)是本地开发环境的经验值,上生产需要根据 LLM 配额和基础设施能力重新调参。但核心架构——请求接入和诊断执行分离、全局执行槽跨进程共享——这个拓扑不需要改,改的是参数。
追问:那执行槽用 Redis ZSET + Lua 做,Redis 本身是单线程的,如果争抢很频繁,Redis 会不会成为瓶颈?
当前场景不会。Lua 脚本只做 ZREMRANGEBYSCORE + ZCARD + ZADD 三个操作,执行时间在微秒级。执行槽的争抢频率取决于诊断任务的提交速率,不是请求速率——请求到执行之间有队列缓冲。即使 100 个 Worker 争抢 10 个槽位,每次 Lua 调用也就几微秒。真正的 Redis 瓶颈更可能出现在限流器的 INCR 高频调用上,但那也是简单的单键操作。
面试官:为什么不用 Kafka?你说 Redis Streams 够用,但 Kafka 不是更成熟吗?
两个原因。一是项目已经依赖 Redis(限流、执行槽、心跳),引入 Kafka 增加一个独立的有状态服务,运维成本上升但当前规模下收益不大。二是瓶颈不在队列吞吐——一个诊断任务跑 30-60 秒 LLM 调用,队列每分钟处理几十个任务就够了,Redis Streams 绰绰有余。Kafka 的优势在海量吞吐、跨数据中心复制和流式计算集成,这些当前用不上。如果告警量到了每秒几千条,或者需要多机房部署,那时候换 Kafka 才有实际收益。
常规问题#
面试官:如果全局执行槽设置为 1 或 10 分别会怎样?
设 1:所有诊断串行,告警堆积时延迟极高,但 LLM/RAG 压力最小。设 10:高并发但 LLM RPM/TPM 可能被打满,Postgres(向量/BM25 检索)和 MCP 工具延迟上升。当前默认 2 是在本地开发环境下的经验值——足够验证并发机制,又不会打爆依赖。生产环境应根据 LLM 配额和基础设施能力调整。
反思与改进#
面试官:这套并发设计的投入产出比怎么样?
队列 + Worker + 执行槽 + 心跳 + DLQ 大概花了两周。如果只做 demo,直接在 API 进程里跑 Agent 就够了。但如果要回答”高并发怎么办、任务丢了怎么办”这些面试问题,就必须有真实的队列和 Worker。从面试角度,这是项目里最能体现系统设计能力的部分,投入产出比很高。