
即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载导读本文以 WuKongIM 仓库中的架构决策记录 ADR-0017《Bound active diagnostics in the Analysis MCP》 为核心系统讲解云端仿真分析网关Analysis MCP中主动诊断active diagnostics能力的边界设计何时允许抓取 CPU profile、堆快照、协程快照与消息跟踪规则每种诊断的时间窗口和累计预算如何被硬性限制以及为什么 shell 执行、服务重启、配置变更、云操作和数据删除被完全排除在工具面之外。读完本文你将理解 WuKongIM 云端压测分析体系如何用封闭工具注册表 严格入参校验 单例诊断互斥 累计预算四层机制让 MCP Agent 在只读观测与最小侵入式诊断之间取得可审计的平衡并掌握每类边界常量的源码级依据。背景为什么只读之外还需要有界的主动诊断在 WuKongIM 的云端仿真工作流中wkanalysis网关为一个具体的 Simulation Run 暴露 Model Context ProtocolMCP接口供分析 Agent 观测运行状态并定位问题。纯只读观测指标、日志、任务审计、运行清单足以覆盖大多数慢路径分析但某些偶发问题——例如 CPU 热点、堆内存泄漏、协程泄漏、特定 UID 或频道的消息投递异常——必须通过主动施加诊断手段才能定位。问题在于主动诊断天然具有扰动性。抓取 CPU profile 会短暂提高进程负载安装消息跟踪规则会改变日志/诊断事件写入路径如果不受约束一个失控的 Agent 可能把一次正常的压测运行变成带病观测甚至掩盖或放大真正要排查的故障。因此 ADR-0017 的核心决策是允许少量、严格有界、逐个节点进行的主动诊断同时把其余一切能改变系统状态的操作彻底排除。ADR 决策原文与核心语义ADR-0017 的完整决策如下docs/adr/0017-bound-active-diagnostics-in-the-analysis-mcp.mdThe Analysis MCP will combine read-only access to run identity, topology, effective scenario, redacted configuration, metrics, service logs, manager diagnostics, task audits, and workqueue state with a small set of bounded active diagnostics. It may capture CPU profiles for at most 30 seconds each and 60 seconds total per Analysis Run, take heap and goroutine snapshots, and install expiring message or send-trace rules, one node at a time. Every active diagnostic records its target and time window so later reasoning can account for perturbation. Tool-level limits must bound time ranges, log lines, series, and response size. Shell execution, service restart, configuration or log-level changes, cloud operations, and data deletion are excluded.把这段决策拆解为四个可执行约束约束维度具体内容诊断类型白名单仅允许 CPU profile、堆快照、协程快照、带过期时间的消息/发送跟踪规则时间预算CPU profile 单次最多 30 秒每个 Analysis Run 累计最多 60 秒跟踪规则带 TTL作用域一次只作用于一个节点one node at a time可审计性每个主动诊断必须记录其目标节点与时间窗口供后续推理修正扰动硬性排除shell 执行、服务重启、配置或日志级别修改、云操作、数据删除一律禁止源码印证边界如何落成硬编码与运行时校验ADR 的决策在仓库中不是概念性的而是通过三层代码落实常量定义预算、入参校验范围、互斥状态机单例。1. 预算常量一次 30 秒、累计 60 秒、TTL 15 分钟所有边界常量集中在 internal/usecase/cloudanalysis/types.goconst ( // MaxMetricRange is the largest query window accepted by one metrics tool call. MaxMetricRange 72 * time.Hour // MaxMetricSamples is the largest requested sample count per series. MaxMetricSamples 5000 // MaxLogLines is the largest log result requested per call. MaxLogLines 200 // MaxDiagnosticsEvents is the largest diagnostics result requested per call. MaxDiagnosticsEvents 500 // MaxTaskAudits is the largest retained task-audit result requested per call. MaxTaskAudits 200 // MaxTraceTTL is the largest active diagnostics tracking lifetime. MaxTraceTTL 15 * time.Minute // MaxCPUProfileSeconds is the per-capture CPU profile ceiling. MaxCPUProfileSeconds 30 // MaxSessionCPUProfileSeconds is the cumulative CPU profile budget per Analysis Session. MaxSessionCPUProfileSeconds 60 defaultMaxResponseBytes 1 20 defaultSourceTimeout 20 * time.Second )这里可以清晰对应 ADR 的每一项承诺单次 30 秒MaxCPUProfileSeconds 30每次运行累计 60 秒MaxSessionCPUProfileSeconds 60跟踪规则必须过期MaxTraceTTL 15 * time.Minute即任何 trace 规则的存活时间上限为 15 分钟工具级结果上限日志单次最多 200 行MaxLogLines 200、诊断事件单次最多 500 条MaxDiagnosticsEvents 500、任务审计单次最多 200 条MaxTaskAudits 200、指标窗口最长 72 小时且单序列最多 5000 个采样点MaxMetricRange/MaxMetricSamples、单次响应体默认上限 1 MiBdefaultMaxResponseBytes 1 20、私有数据源默认超时 20 秒defaultSourceTimeout 20 * time.Second。2. 入参校验Profile 请求的合法形态在 internal/usecase/cloudanalysis/service.go 中validProfileRequest严格限定请求形态func validProfileRequest(req ProfileCaptureRequest) bool { switch req.Kind { case ProfileCPU: return req.Seconds 1 req.Seconds MaxCPUProfileSeconds case ProfileHeap, ProfileGoroutine: return req.Seconds 0 default: return false } }也就是说CPU profile 的秒数必须在1 ~ 30之间堆快照和协程快照属于瞬时快照秒数必须为 0任何其他 kind 直接返回非法。配合 types.go 中的ProfileKind枚举cpu、heap、goroutineAgent 无法通过自由字符串注入任意 profile 类型。3. 单例互斥与累计预算一次只能有一个主动诊断Service结构体维护了诊断状态机service.godiagnosticMu sync.Mutex profileRunning bool activeTraceUntil time.Time cpuProfileUsedSecs intProfileCapture与TraceStart在真正调用数据源之前都会先加锁检查s.diagnosticMu.Lock() if s.profileRunning || s.activeTraceUntil.After(s.now().UTC()) { s.diagnosticMu.Unlock() return Observation{}, ErrDiagnosticBusy } if req.Kind ProfileCPU { if s.cpuProfileUsedSecsreq.Seconds MaxSessionCPUProfileSeconds { s.diagnosticMu.Unlock() return Observation{}, ErrDiagnosticBudgetExceeded } s.cpuProfileUsedSecs req.Seconds } s.profileRunning true s.diagnosticMu.Unlock()这段代码同时实现了三个语义单例诊断profileRunning或activeTraceUntil任一非空新诊断请求直接返回ErrDiagnosticBusy——CPU profile、堆快照、协程快照、trace 规则之间互斥永远只有一个活跃累计预算cpuProfileUsedSecs req.Seconds MaxSessionCPUProfileSeconds时返回ErrDiagnosticBudgetExceeded即每次 Run 的 CPU profile 总时长不可能超过 60 秒失败回滚若底层捕获失败会比对activeTraceUntil是否仍是本次预留值是则清零service.go避免失败请求消耗预算或卡死互斥锁。相关错误类型同样有明确语义types.goErrDiagnosticBusy其他诊断捕获进行中与ErrDiagnosticBudgetExceeded累计诊断预算耗尽Agent 可据此决定稍后重试或放弃。4. Trace 规则目标白名单 强制 TTLTraceStart只接受两类跟踪目标service.govalidSelector : req.Target sender_uid strings.TrimSpace(req.UID) ! len(req.UID) 256 || req.Target channel strings.TrimSpace(req.ChannelID) ! len(req.ChannelID) 256 req.ChannelType 0 if !s.validNode(req.NodeID) || !validTraceTarget(req.Target) || !validSelector || req.TTL time.Second || req.TTL MaxTraceTTL { return Observation{}, ErrInvalidToolInput }目标只能是sender_uid或channelvalidTraceTarget选择器必须配套sender_uid需要非空 UIDchannel需要非空 ChannelID 且 ChannelType 0TTL 必须在 1 秒到 15 分钟之间——跟踪规则必然过期不存在永久跟踪node_id必须属于白名单节点集validNode保证一次一个节点。5. 节点白名单与运行身份绑定one node at a time 的前提是节点集本身封闭。cloudanalysis.New构造时会把允许的节点 ID 放入map[uint64]struct{}service.go任何请求中的node_id不在集合内都会触发ErrInvalidToolInput。同时每个工具请求都必须携带精确的RunID与会话绑定的s.runID不一致即返回ErrRunIdentityMismatchservice.go确保诊断永远作用于正确的这一次运行。只读观测面与主动诊断互补的完整工具注册表ADR 明确只读访问是主体主动诊断只是补充。在 internal/access/cloudanalysismcp/handler.go 的registerTools中每个工具都带toolAnnotations标注只读或主动属性工具类别作用run_inspect只读证明精确的 Run Identity 与当前存活/已释放库存状态cluster_snapshot只读有界的聚合节点与 workqueue 快照workload_inspect只读运行中的负载 worker 连接诊断或终态 wkbench 摘要、阶段窗口与结构化失败metrics_query_range只读执行服务端白名单内的 PromQL 表达式固定 query_idlogs_search/logs_context只读在单个白名单节点上检索普通应用日志 / 围绕不透明游标分页diagnostics_query只读检索保留的诊断事件按 TraceID、ClientMsgNo、ChannelKey、UID、Stage、Result 过滤task_audits_query只读检索保留的 Controller 任务历史config_read_redacted只读读取单节点允许列表内的脱敏有效配置trace_start/trace_query主动安装一个过期的跟踪规则 / 查询其保留事件profile_capture/profile_top/profile_list主动捕获 CPU/堆/协程 profile / 返回有界符号摘要 / 列出捕获元数据值得注意的是metrics_query_range与logs_search的细节边界指标查询只能按query_id选择服务端预定义的 PromQLs.metricQueries[req.QueryID]见 service.goAgent 无法传入任意 PromQL时间窗口上限 72 小时、步长 1 秒到 15 分钟、采样点上限 5000违反任一条件即ErrInvalidToolInput日志检索的 keyword 上限 128 字符、来源只能是app/error、级别只能是debug/info/warn/error/fatal且最多 5 个、单次最多 200 行service.go。扰动可审计性每个 Observation 都记录窗口与完整性ADR 要求每个主动诊断记录其目标与时间窗口以便后续推理考虑扰动。这在统一响应包络Observation中落地types.gotype Observation struct { RunID string json:run_id Node string json:node Source string json:source ObservedAt time.Time json:observed_at Window *TimeWindow json:window,omitempty Completeness Completeness json:completeness Warnings []string json:warnings Data any json:data }Window记录本次观测或主动扰动的精确时间区间profile 抓取、trace 生效的起止Completeness区分complete / partial / unavailable明确告知数据是否因截断或源失败而不完整Warnings承载截断、源失败等显式说明。finish方法service.go在返回前还会把整个响应序列化并检查maxResponseBytes超限返回ErrResponseTooLarge从根上杜绝 Agent 侧因响应过大引发二次问题。分析 Agent 拿到这些元数据后可以区分profile 抓取期间 CPU 升高与负载本身异常。网关组装边界如何注入每一次运行在 cmd/wkanalysis/main.go 中wkanalysis进程把运行身份 数据源 会话凭证组装成 Analysis 网关通过 internal/app/cloud_analysis.go 的NewCloudAnalysisGatewayHandler组装RunInspector静态或 Provider 库存证明、NewHTTPSources管理器、Prometheus、节点 API 的私有源与cloudanalysis.Service每个网关与一个精确RunID绑定RunExpiresAt决定运行租约到期时间会话层 cmd/wkanalysis/session.go 签发的 Analysis Token 有效期最长为 45 分钟且不能越过租约前 5 分钟且要求在租约剩余至少 30 分钟时才可签发——诊断窗口整体被运行租约锁死MCP 端点本身只接受 bearer 凭证auth.RequireBearerToken作用域固定为wukongim:analysis并启用跨域保护handler.go。配合 ADR-0030《Bound each analysis access window》与 ADR-0034《Use run-scoped internal capability tokens》可以理解主动诊断预算不是全局共享的而是每个 Run 独立结算——cpuProfileUsedSecs是Service实例字段属于该 Run 的会话私有状态。边界之外的明确禁区ADR 最后一句划出了不可逾越的红线shell 执行、服务重启、配置或日志级别修改、云操作、数据删除全部排除。这在实现层面由多重机制保证工具注册表封闭registerTools只注册上文列出的有限工具MCP 端点上不存在任何shell_exec、restart、update_config、delete类工具入参不接收任意路径/URL/命令cloudanalysis包注释明确从不接受任意 URL、文件、命令或进程选择器types.go仅 JSON 响应config_read_redacted只返回允许列表内的脱敏配置原始 profile、worker 文本、URL 与文件系统细节保持私有见 internal/access/cloudanalysismcp/FLOW.md。换句话说即使 Agent 被诱导或出错协议层也不存在通向变更操作的路径。边界契约的测试保障仓库通过契约测试锁死这些边界防止后续重构悄悄放宽限制。例如 internal/access/cloudanalysismcp/boundary_contract_test.go 与 internal/usecase/cloudanalysis/service_contract_test.go 会验证非法节点、超限 TTL、超预算 CPU 时长、错误 RunID 等场景均返回既定错误。分析网关相关的集成与契约测试可进一步查阅 cmd/wkanalysis/runtime_contract_test.go 以及仓库根目录的 cloud_sim_analyze_test.go。小结四层机制构建可审计的最小扰动层机制对应源码预算常量层单次 30s / 累计 60s CPU、TTL 15min、日志 200 行、响应 1MiBtypes.go入参校验层Profile kind/seconds、trace target/selector/TTL、节点白名单、RunID 绑定service.go互斥状态机层一次仅一个活跃诊断、CPU 预算累计、失败回滚service.go协议封闭层封闭工具注册表、仅 JSON、无 shell/重启/删除路径handler.go对于在 WuKongIM 云端仿真中排查疑难问题的工程团队这套设计提供了可直接借鉴的范式给 Agent 的诊断能力设数量、时长、范围三重预算让每次扰动都留下时间戳与目标标识再把一切变更操作从协议面物理移除。这样分析 Agent 既能完成 CPU 热点、内存泄漏与定向消息路径的深度排查又不会干扰压测数据的可信度——这正是有界的主动诊断相对于无约束运维权限的核心价值。赞分享即时通讯后端【免费下载链接】WuKongIMMore than just IM 不只是即时通讯(IM)项目地址https://gitcode.com/gh_mirrors/wu/WuKongIM点击查看免费下载相关推荐WuKongIM Cloud Analysis MCP 工具契约运行级诊断的只读观测面与边界设计WuKongIM Cloud Analysis MCP 工具契约运行级诊断的只读观测面与边界设计 本文以 WuKongIM 仓库内 Analysis Skil即时通讯后端WuKongIM 云仿真诊断架构解析Analysis MCP 与 Analysis Skill 的职责分离设计WuKongIM 云仿真诊断架构解析Analysis MCP 与 Analysis Skill 的职责分离设计 云仿真压测Cloud Simulation即时通讯后端WuKongIM 云端压测运行分析指南基于 Analysis MCP 的实时故障诊断与判定方法论WuKongIM 云端压测运行分析指南基于 Analysis MCP 的实时故障诊断与判定方法论 本文基于仓库 .agents/skills/wukongim即时通讯后端上一篇CameraKit iOS核心功能详解照片与视频拍摄的完美解决方案下一篇Aves 版本演进全解析从 CHANGELOG 透视 Flutter Android 媒体库的功能架构与工程实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考