新闻详情

新闻详情

首页 / 资讯中心 / 详情

Agent编排平台底层重构实录:从单点调度到高并发分布式架构

发布时间:2026/10/1 10:36:28来源:尧图网络
Agent编排平台底层重构实录:从单点调度到高并发分布式架构
去年底的一次线上事故让我彻底下定决心Orkas 这个 Agent 编排平台必须做一次底层重构。当时的情况是Orkas 已经跑着上百个业务 Agent从代码生成助手到数据清洗任务都有。某天晚高峰业务方做了一次简单的扩容操作结果触发了调度器全局限流——所有正在执行的 Agent 任务被强制排队页面上一大片任务卡在 pending 状态超过二十分钟。我去查调度器节点CPU 占用不到 30%内存也宽裕但就是没人能说清楚任务为什么全堵住了。翻代码才发现调度器既不做分片又把全局状态全塞在内存里扩容反而加剧了状态扫描的负担。这篇文章记录的就是这次重写 Agent 地基的完整过程旧架构的致命伤在哪里、重写时我怎么选型、新地基的核心设计是什么、迁移路上踩过哪些坑以及最终用数据验证的效果。如果你正在做 Agent 框架、任务编排或者高并发系统相关的工作这篇文章应该能帮你省下不少弯路。1. 为什么必须动地基旧架构的三个致命伤1.1 单点调度器全局状态无处安放Orkas 的旧版本是我在项目早期为了快速验证 Agent 能力搭的。当时的假设很简单Agent 数量不超过 50单节点部署调度器用一个 goroutine 轮询任务队列。这个设计在 demo 阶段完全没问题但到了生产环境问题开始像滚雪球一样堆积。我把旧架构的拓扑简化描述一下系统里有一个 dispatcher 角色持有整张内存任务表用一个 channel 接收新任务另一个 goroutine 负责把任务分发到 worker 池。每次分发时它需要遍历全表来确认依赖关系、检查 Agent 注册状态、计算资源占用然后才把任务塞给 worker。问题出在扩展性上。当任务数量突破千级单机轮询的成本不是线性上涨而是平方级上涨——因为每次扫描全表都要判断每个任务和其他所有任务的依赖关系。我们后来加了一些索引来缓解但本质上单调度器的 O(n²) 扫描已经把整个平台的吞吐锁死了。更麻烦的是全局状态全部放在调度器内存里一旦调度器重启所有 Agent 任务的状态全部丢失。当时的兜底方案是任务超时后重新入队结果就是大量 Agent 重复执行相同请求下游系统的幂等负担极重。所以重写的首要目标非常明确把调度器从单点变成集群把状态从内存迁到持久化存储。1.2 执行引擎的签收即完成错觉旧执行引擎里有一个让我非常头疼的设计——任务被 worker 签收后调度器就把它标记为 running但 worker 到底跑得怎么样调度器完全不感知。Agent 进程一旦僵死比如外部 API 调用挂起、goroutine 泄漏、依赖的模型服务超时任务就会一直停留在 running 状态没有任何机制把它捞回来。当时我们用一个固定 30 分钟的全局超时来兜底但对很多 Agent 任务来说30 分钟太长了而且超时后只是简单重试完全不知道任务之前执行到哪一步。做过 Agent 开发的同学都懂Agent 的每一步都可能调用外部工具、大模型接口一旦中途失败重试成本非常高——重来一轮不仅耗时还可能产生重复调用费用。这个问题的根源在于执行引擎把任务签收当成了任务完成的等价事件缺少心跳和阶段进度上报。重构后我设计了一套四段式生命周期pending → executing → checkpoint → completed/failed让调度器能感知 Agent 任务在每个阶段的真实状态。这是整次重写里性价比最高的一个改动。1.3 点对点通信多 Agent 协作的隐形天花板再往下看通信层也埋着雷。旧版 Agent 与调度器之间通过 WebSocket 长连接直连每个 Agent 一条连接。听起来简单但生产环境里 Agent 需要跟多个服务协作模型网关、工具执行器、日志服务直连模式让连接数爆炸式增长。有一段时间模型网关经常被连接数打满排查下来发现一半连接都是 Orkas 的 Agent 发出去的探活心跳。更麻烦的是直连模式天然不支持多 Agent 协作。现在社区里经常讨论Agent 框架与编排到底怎么落地我的经验是如果通信层只是点对点你很难做出像样的协作拓扑。Agent 之间要做任务传递、结果共享、上下文同步靠点对点硬连会变成蜘蛛网。所以这次重构我把通信层整体换成了事件总线模式Agent 之间通过主题topic解耦调度器只负责路由事件不再关心具体连接。这三层——调度、执行、通信——就是我要重写的全部内容。与其说是重构不如说是把地基拆了重浇。接下来一个月的时间我按下面的方案推进。2. 重写前的关键决策选型、边界与兼容策略动手之前我先给自己定了三条原则避免重写变成无底洞不追求一步到位先保证旧业务能平移、新架构能跑通所有重写的改动都要有对应压测数据支撑重写过程中每天保持主干可部署。2.1 技术选型为什么是 Etcd 事件总线先说状态存储。原来是纯内存我要找一个能解决集群一致性和任务可恢复的方案。当时在关系型数据库MySQL/PostgreSQL和 Etcd 之间犹豫了很久。数据库的好处是生态成熟、团队熟悉但在任务状态变更频繁 分布式锁 选主这些场景下数据库需要额外做很多约束——乐观锁、唯一索引、事务隔离级别调优写起来很别扭。Etcd 的优势则是天然支持 Watch 和分布式锁非常适合调度器集群选主和任务元数据存储。我最终选了 Etcd 存任务元数据 调度器选主真实执行数据仍走消息队列。为什么不全部放 Etcd因为 Etcd 本质是一个强一致 KV大批量写入在高并发下是扛不住的。我预估任务状态变更的峰值 QPS 在 5k 左右这个量级如果全打 Etcd 会吃亏。所以设计上刻意做了冷热分离热路径任务事件流走 Kafka 事件总线冷路径任务状态、历史记录走 Etcd 对象存储归档。现在搜索AI Agent 怎么扛并发能找到一大堆方案但核心思路往往就一条把高频状态变更和低频元数据分开别让一个存储扛所有。2.2 重写边界哪些东西坚决不改这次重写我给自己画了很清楚的边界不重写 Agent SDK 的对外 API保证业务 Agent 代码几乎不用动不重写 Agent 内置技能的注册方式只调整注册后的调度逻辑不重写监控看板的展示层只改数据上报链路不重写权限模型。这个决定事后证明非常关键。如果连 API 都一起改迁移成本会指数级上升而且出问题后你很难定位是新功能 bug 还是重构引入的 bug。保持 API 兼容才能做到新地基、旧房子让重构风险可控。2.3 灰度策略新老架构双跑两周切换新老架构我没有用标志位一键切而是选了双跑模式把新调度器作为影子系统接入生产流量但它不实际影响任务执行只是把同样的任务流在新旧两套系统里各跑一遍对比结果。这个阶段我跑了整整两周每天比对任务状态偏差、延迟分布、失败率。有人觉得双跑浪费资源但我的体会是底层重构最贵的不是写代码而是发现隐藏的暗坑。双跑期间我们抓到了至少 7 个只在生产环境才会暴露的问题比如一个 Etcd 租约续期导致的任务丢失、一个 Kafka 分区分配不均引发的热点。这些问题如果直接切流量每一件都可能变成 P0 事故。3. 新地基的核心设计调度、执行、状态三位一体接下来是新架构的核心设计。我分三条线来讲调度内核怎么设计、执行引擎怎么感知 Agent 进度、状态同步怎么保证一致性。3.1 调度内核从单点轮询到分片协调新的调度器不再是单个节点而是一个调度器集群。我采用一致性哈希加粘性分片的方式每个任务根据 agent_id 哈希后落到固定的分片每个分片由集群中的某个调度器节点负责。这个设计带来的直接好处有三个调度器可以水平扩展加节点就能均摊任务扫描压力任务和它的调度器有粘性调度器可以本地缓存任务上下文减少跨节点查询某个调度器挂掉时只有它负责的分片需要重新选主调度其他分片完全无感知。调度循环也从全表扫描改成了基于优先级的双队列模型一个优先队列放紧急任务人工触发、SLA 敏感任务一个普通队列放批量任务。调度器每次循环先取紧急队列头部再按权重取普通队列任务。这个设计带来的最直接收益是紧急任务的 P99 等待时间从 2.4s 降到了 120ms。为什么用一致性哈希而不是简单的随机分配原因很简单Agent 任务是有状态的。如果同一个 agent_id 的任务被随机分到不同调度器那每个调度器都要去 Etcd 反复拉取这个 Agent 的上下文不但慢还会因为并发写引发版本冲突。粘性分片让同一 Agent 的任务尽量落在同一分片把热数据留在本地这是性能和一致性双赢的选择。3.2 执行引擎把 Agent 当作有内部状态的状态机旧引擎最大的问题是签收即完成。新引擎我改成了阶段上报 心跳续期机制。具体来说每个 Agent 任务的状态机被拆成四个阶段pending → executing → checkpoint → completed或 failedAgent SDK 在执行关键步骤调用大模型、调用工具、返回中间结果时会主动上报 checkpoint 事件调度器通过 Etcd 的租约来管理任务的心跳租约过期且 Agent 未汇报任务就会被判定为失联进入崩溃恢复流程。这里有一个很容易被忽略的设计checkpoint 事件不仅是进度上报更是恢复锚点。如果 Agent 进程中途被 kill 掉重启后可以从最近一次 checkpoint 继续而不是从头再来。顺便说一句网上大量agent execution terminated due to error的问题很多就是缺少 checkpoint 机制导致的。Agent 执行过程长、依赖外部服务多没有锚点的任务一崩就要重来成本极高。3.3 状态同步不滥用 Etcd Watch 的分层读取Etcd 在集群里承担两个角色选主协调器和任务状态存储。这里容易犯的错误是让所有 worker 都去 watch 所有任务变更那会把 Etcd 拖垮。我采用了一层本地缓存 版本号校验的方案每个调度器只 watch 自己负责的分片事件worker 通过消息队列收到任务执行指令后需要读取任务状态时先读本地缓存缓存 miss 才回源到 Etcd并发冲突用版本号做乐观锁冲突时重试。实测下来这个设计把 Etcd 的 QPS 压得很低。集群 30 个节点、5000 个在线任务时Etcd 的读写 QPS 只有 800 左右远低于它的承受极限。4. 迁移路上的实战记录六个典型坑重写代码用了三周踩坑和调优用了近半个月。下面这六个坑每一个都值得单独写一篇我挑最有代表性的记录在这里。4.1 死锁缓存预热与锁顺序新架构刚上测试环境时我发现一个诡异现象任务被分配到一个新调度器节点后第一个任务总是异常慢P99 飙升到 8 秒。排查后发现原因是本地缓存冷启动——新节点没有任何缓存任务过来时缓存 miss全部打到 EtcdEtcd 又是串行处理形成了一波集中访问。更麻烦的是锁竞争调度器在处理任务时需要同时持有任务分片锁和Agent 上下文锁两个锁的获取顺序不一致时就会产生死锁。最开始我没意识到问题的严重性直到一次压测把整个调度器集群的 goroutine 全锁死任务全部 timeout。解决分两步一是预热新节点启动时主动从 Etcd 把本分片的 Agent 上下文预加载到内存二是锁顺序规范化所有代码必须按先分片锁、后上下文锁的顺序获取并且引入锁超时机制避免无限等待。4.2 幂等性消息队列的重复事件事件总线带来的老生常谈却依然致命的坑重复事件。生产环境下 Kafka 的 at-least-once 语义会带来重复消息。旧架构没有幂等设计因为点对点模式下消息不会重复换成事件总线后重复消息导致的重复任务、重复扣费、重复告警统统出现了。排查链路是这样的先是下游服务报告同一份数据被处理了两遍我去查 Kafka 消费位点发现确实有 offset 被重复拉取再到调度器这边看发现消费逻辑里没有做去重——每条消费记录都直接调用创建任务入口。而创建任务入口没有幂等键于是重复任务就产生了。修复方案是给每个任务事件加一个全局唯一的 trace_id调度器在消费端做一个已处理 ID的布隆过滤器加 Etcd 持久化记录处理前先查询处理后再写记录。这个改动让重复事件的影响面降到几乎为零。4.3 超时控制一刀切是最大的坑旧架构里的 30 分钟超时在新架构里被证明是最难迁移的部分。原因是 Agent 任务的真实时长跨度极大有的任务只需要 5 秒比如一次简单的文本分类有的要跑 2 个多小时比如长文档分析、多轮网页爬取。一刀切的超时策略在旧架构就饱受诟病我趁机重构了超时模型。新超时模型分两层任务级超时由 Agent 开发者在注册任务时显式声明不给默认值阶段级超时每个 checkpoint 周期内允许的最长间隔超过就认为 Agent 失联。这里踩过的坑是刚开始我给任务级超时设了一个默认值 30 分钟结果那批长任务全被切了业务线直接炸锅。改成分层模型后长任务可以在 checkpoint 阶段持续续命短任务可以精确超时不再互相影响。4.4 Etcd 租约续期与时钟漂移Etcd 租约续期这里有一个非常隐蔽的坑。调度器节点通过 gRPC 向 Etcd 发送租约续期请求正常情况下没问题但生产环境的网络偶发抖动会让续期请求延迟。如果 Etcd 认为租约过期它会删除关联的所有 key——这可能导致任务元数据直接蒸发。我一开始没意识到这是租约问题现象是任务状态突然消失查了日志才发现 Etcd 侧删除了 key。后来做了两个改动一是加大租约 TTL 并加长续期间隔容忍网络抖动二是给任务元数据的删除加了保护逻辑——只有调度器明确调用完成任务接口时才能删除租约过期只触发任务失联状态不直接删除元数据。这个坑是双跑阶段发现的如果没有影子系统生产环境大概率会直接出数据丢失事故。4.5 数据迁移内存状态怎么搬到 Etcd老任务的状态全在内存里迁移那天我面临一个尴尬局面老任务的状态救不回来。我最后采用分段放弃策略三天以内的活动任务在迁移窗口内强制跑完或标记失败更老的历史任务允许丢失状态但保留执行日志用于审计。这个决定当时顶着不少压力但事后看是对的——为了少数历史任务拖住整个迁移窗口风险远大于收益。迁移时我写了一个双写脚本老调度器每产生一条新状态就同步写一份到 Etcd 的 shadow key验证两边数据一致后再切换。这个双写持续了 48 小时两边数据完全对得上才算迁移完成。4.6 监控盲区看不到的指标最危险重构期间我最大的教训是监控一定要提前铺不要等出了问题再补。迁移到新架构的头两天我几乎没有发现任何异常不是因为没问题而是因为新架构的监控指标还没接好旧看板根本看不到新指标。后来我补了几个关键监控任务状态流转延迟、Etcd 读写 QPS 与延迟、分片调度器主备切换次数、事件总线消费 lag。这几个指标后来救了我们很多次——比如有一次事件总线消费 lag 突然从 100 飙到 5 万就是靠这个指标提前发现的否则下游系统要被冲垮。5. 重构后的成效压测数据与长期收益5.1 压测对照新架构到底强在哪里重构稳定运行两周后我做了一次完整对照压测。为了控制变量新旧架构都跑在同样的 10 节点集群上模拟同样的 Agent 任务负载任务量 3000时长从 5 秒到 20 分钟不等。关键数字如下指标旧架构新架构调度器最大任务吞吐任务/s3202100紧急任务 P99 等待时间2.4s120ms任务执行失败率排除业务错误3.7%0.4%断点恢复成功率0%靠全局超时重启92%调度器节点故障切换时间10min需人工干预8s单节点可支撑任务数90022000这个结果说明什么调度吞吐提升主要来自分片并行和去掉全表扫描失败率大幅下降则全靠 checkpoint 机制和心跳续期。最让我满意的其实是故障切换时间一次晚上的节点宕机8 秒内另一个节点接管了分片业务基本无感知。这放在旧架构里至少是二十分钟的人工抢险。5.2 稳定性收益几个无法量化的改变性能数据只是一部分。重构带来的稳定性收益有些很难用数字量化但对团队意义更大Agent 崩溃恢复成为常态能力任务不再一崩就重来多 Agent 协作终于有了可靠的通信底座事件总线让不同 Agent 之间通过 topic 解耦协作拓扑可以任意编排深入理解了调度器和执行器分离的设计哲学后续再扩展新 Agent 类型时有据可依。也正因为这次重写Orkas 开始被团队内部其他项目复用比如数据分析管线和定时报告生成都是基于新的调度内核来构建的。另外事件总线这套通信底座天然支持给消息加标签做权限控制这让Agent 安全的落地变得顺理成章——敏感 topic 只有特定 Agent 能订阅而不是像以前那样所有连接都能探到全局事件。5.3 给想做同类重构的人几条实用建议最后我结合这几个月的实战经验给打算做类似底层重构的读者几条建议如果重构的系统是线上核心务必做双跑灰度至少跑满一个完整业务周期别急着切流量重构前先定义好成功标准比如 P99、失败率、故障切换时间的具体目标并在重构后用同一基准对照Agent 类系统一定要有 checkpoint 设计这可能是所有改造里投入产出比最高的一个点不要迷信单一存储高频事件流和冷状态存储分开设计能让整个架构的扩展性上一个台阶监控指标要在切流量之前铺好重构期间看不到数据等于蒙眼开车。这次重写让我体会最深的一点是所谓地基重构最难的其实不是写代码而是识别出那些看似正常实则隐患的设计假设。旧架构在 demo 阶段一切正常但每个正常背后都藏着一条会在大规模下崩掉的暗线。把地基挖开重浇需要极大的决心和耐心但浇好之后上面的 Agent 业务才能真正跑得稳、跑得远。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Python安装从零到Hello World:环境配置与常见问题详解 2026/10/1 11:23:23

Python安装从零到Hello World:环境配置与常见问题详解

1. 项目概述:为什么要把"安装Python"这件事单独讲清楚 我接触Python的时间不算短,这几年看着它从一门"脚本语言"变成数据分析、自动化办公、人工智能落地时绕不开的基础工具。但无论是带新人入门,还是帮同事排查环境&…

阅读更多 →
JSP网上拍卖系统实战:从环境搭建到竞价核心逻辑 2026/10/1 11:23:22

JSP网上拍卖系统实战:从环境搭建到竞价核心逻辑

简介:本资源是一套基于JSP技术实现的网上拍卖平台毕业设计完整方案,面向计算机专业本科生及Web开发初学者,适用于课程设计、毕设选题与Java Web项目实践。压缩包共236个文件,以51个JSP页面为核心构建前后端交互逻辑,辅…

阅读更多 →
Oracle主键自增方案详解:序列、触发器与IDENTITY列对比 2026/10/1 11:23:22

Oracle主键自增方案详解:序列、触发器与IDENTITY列对比

用惯了MySQL的人转过来用Oracle,第一件事就是会发现建表的时候没有AUTO_INCREMENT这种写法。网上搜一圈,答案五花八门:序列、触发器、IDENTITY列、GUID……看着都行,但没人讲清楚到底该用哪个、为什么用、坑在哪里。这篇文章就把O…

阅读更多 →
基于CAD/CAE的V型往复式压缩机设计全流程解析 2026/10/1 11:23:22

基于CAD/CAE的V型往复式压缩机设计全流程解析

做非标机械设备设计这些年,经手过不少压缩机组的设计任务,其中V型往复式活塞压缩机算是比较有代表性的一类。这类机型在中小排量的高压场合用得非常多,像空压站、CNG加气站、石油化工的辅助气源,甚至一些船用和车载的增压系统里都…

阅读更多 →
C# P/Invoke底层原理与access violation c0000005排查实战 2026/10/1 11:23:21

C# P/Invoke底层原理与access violation c0000005排查实战

做过几年上位机相关开发的人,对P/Invoke应该都不陌生。C#要调Windows API,或者调用厂商提供的C/C动态库,绕不开这个东西。表面上看,写个[DllImport]声明,然后就能像调用普通C#方法一样调原生函数,挺顺的。但…

阅读更多 →
JSP人事系统实战:可运行毕设源码与部署避坑指南 2026/10/1 11:23:15

JSP人事系统实战:可运行毕设源码与部署避坑指南

简介:本资源是一套面向Java Web初学者与高校计算机专业学生的实践型教学项目,聚焦JSP动态网页开发与人事管理业务建模。通过完整复现一个具备员工信息管理、考勤记录、薪资计算等核心功能的B/S架构系统,帮助学习者掌握Servlet-JSP协同开发、J…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉