尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

AI辅助构建离线告警规则引擎:运维巡检实践

AI辅助构建离线告警规则引擎:运维巡检实践 先交代一下背景这段时间我在做一个边缘机房的巡检项目20多台服务器分布在不同的内网网段网络时好时坏唯一稳定的是本地的采集脚本。原来的告警判断基本靠一堆shell脚本if-else拼出来每台机器规则还不一样值班同事每次接手都要先翻半天文档。这次我想换一个干净的做法也想认真体验一下华为云CodeArts上的AI智能体到底能在实际开发里帮上多大忙。于是就有了这个项目一个脱离云端也能独立运行的离线告警规则引擎再配一个运维巡检小程序做交互入口。文章会把需求梳理、规则引擎设计、AI辅助编码、小程序联调整个过程过一遍途中踩的坑也会一并写下来。想了解规则引擎落地细节或者对AI辅助开发真实效果感兴趣的朋友可以直接挑自己关心的章节看。1. 项目背景与整体设计思路1.1 告警规则为什么会成为运维的“血泪账”做过运维的人应该都有同感线上告警规则往往不是设计出来的而是“长”出来的。最早是crontab里的一个脚本判断df -h输出发现超过80%就发邮件。后来加了数据库、Redis、Nginx每个模块都有人顺手塞一段自己的判断逻辑有的写在Zabbix触发器里有的写在监控平台的自定义公式里还有的直接记在某个同事的Excel表里。等到真正出了问题要去翻一条“历史上调过阈值”的规则需要把所有系统都查一遍更麻烦的是不同人写的判断标准还不一致。我这次做的项目起因是一次典型的漏报事故某台机器根分区正常数据盘使用率已经到了92%但旧脚本只检查了根分区。磁盘报警没触发业务第二天早上才被拖垮。类似的问题反复出现后我就考虑把告警判断逻辑统一成一个独立的规则引擎规则以结构化文件管理可以评审、可以版本化、可以随巡检包一起下发。关键是这套引擎必须能离线工作因为边缘机房的网络经常断一旦依赖云端告警平台断网期间漏报只能靠人工巡检兜底。另外一个推动力是规则变更的“随意性”。传统模式下改一条阈值直接改脚本没有人知道这是谁在什么时间改的也没有回滚手段。把规则收拢到引擎之后每一条规则都有唯一的ruleId、版本、生效时间和管理人等于把监控配置从“手工作坊”变成了“工程化交付”。这也是我选择重新做一个告警规则引擎而不是继续在脚本上打补丁的根本原因。1.2 为什么选华为云CodeArts的AI智能体来辅助开发做这个项目之前我在团队里推过一段时间的DevSecOps流程华为云CodeArts这个平台我们本来就有关注。它覆盖了需求管理、代码托管、流水线、CI/CD、以及一些AI能力核心是把研发过程拉通到一个平台里面。这次我想验证的不只是CodeArts的仓库和流水线能力更重要的是它的AI智能体到底能不能在“写规则引擎”这种逻辑密集型的模块里真正帮上忙。规则引擎这个模块的特点是边界清楚、接口明确、但写起来重复度高。大量比较运算、时间窗口判断、异常分支处理代码结构很相似可每一处都要仔细考虑边界条件。这种任务其实非常适合AI辅助输入输出好描述测试用例好设计生成结果也容易用单测验证。比让AI写一个“理解业务上下文”的业务系统靠谱得多。所以我决定把规则引擎的主干代码、单元测试、以及MR阶段的代码检视都交给CodeArts来做一轮实战检验。当时在IDE里启用CodeArts插件后我首先试的不是让它直接生成完整项目而是先让它生成一个可运行的模块骨架然后通过不断的提示词调整逐步把细节补齐。整个过程有惊喜也有不太满意的地方后面第3章会详细写。选型的关键结论是AI智能体适合当编程搭档不适合当“甩手掌柜”尤其像规则引擎这种将来要背告警责任的代码最终逻辑必须由人来确认。1.3 整体架构离线规则引擎和小程序怎么分工整个系统的结构其实不复杂重点是划清边界。数据来自每台机器上的采集AgentAgent定时采集CPU、内存、磁盘、进程、端口等信息写到本地的轻量数据库或JSON文件中。规则引擎从这些本地数据里读取指标加载规则配置执行匹配产生告警事件。告警事件同时做两件事一是落到本地SQLite二是在局域网内通过HTTP接口暴露给运维巡检小程序。这里要特别说明“离线”体现在哪。离线不仅指断网后本地依然能算还指规则引擎本身不依赖云端服务。规则包是提前打包下发的引擎在本地加载后即使外部网络完全断开也能基于最新采集的数据做判断结果先落盘等网络恢复后再批量上报。小程序这边我刻意没有让它承担规则计算因为微信小程序包体有限制运行环境也不适合放一个复杂的规则引擎。小程序只做三件事展示告警、触发手动巡检、管理规则包。引擎负责计算小程序负责交互各干各的活。这样的分工还有一个好处如果以后不需要小程序可以直接在浏览器里打开引擎的H5页面或者接一个命令行的alert列表架构不用变。数据层、规则层、展示层解耦之后后续扩展才有空间。2. 核心模块拆解离线告警规则引擎2.1 离线引擎和在线告警平台的本质差异我们经常接触的监控告警平台比如网管平台、云监控大多是“在线模式”Agent采集数据后实时上报到中心中心统一执行规则再触发送信、短信、电话通知。这种模式的优点是集中管理所有机器一套规则权限好控制。缺点是网络一断告警就变成瞎子如果数据涉及隐私或合规更不能轻易全部上云。离线规则引擎的思路正好相反它把规则判断下沉到边缘节点采集、计算、存储都在本地完成。对于运维巡检来说这个模式的意义不只是“断网也能用”更重要的是低延时。数据不需要经过一次网络往返采集到判断在本地毫秒级完成。而且规则引擎本身非常轻不依赖重型框架树莓派、工控机、普通x86小盒子上都能跑非常适合边缘机房和分支机构的巡检场景。设计的时候我给引擎定了几个硬性指标第一规则文件只允许是纯文本比如JSON或YAML不能依赖数据库表第二引擎除了解析规则和做判断不负责采集数据采集的事留给Agent第三告警输出必须是结构化的事件至少包含ruleId、级别、指标值、时间戳方便下游处理。这样即使以后换了采集端规则引擎也不用改。2.2 规则配置设计一条告警如何用JSON描述规则引擎的第一步是定义清楚规则长什么样。我用JSON表达每条规则既能被人读也能被程序解析。以“数据盘使用率持续过高”为例一条规则是这样{ ruleId: disk-data-usage-critical, name: 数据盘使用率持续过高, metric: disk_data_usage, operator: greaterThan, threshold: 90, duration: 300, level: critical, enabled: true, suppress: 1800 }关键字段的作用如下表所示字段说明示例ruleId规则唯一标识全系统唯一disk-data-usage-criticalname规则可读名称用于界面展示数据盘使用率持续过高metric指标名引擎从采样数据里取这个字段disk_data_usageoperator比较运算符greaterThanthreshold阈值与指标值比较90duration持续时间窗口单位秒300level告警级别info / warning / criticalenabled是否启用truesuppress告警抑制时间单位秒1800这里最容易被忽略的是duration字段。如果采集周期是60秒一次表达“持续5分钟”需要连续5个采样点都满足如果采集周期是30秒一次则需要连续10个点。我一开始在旧脚本里直接写“连续5次”后来发现不同机器的采集周期不一致导致一台机器半小时就报警、另一台要一小时。改成“持续300秒”后引擎内部按照实际采样时间戳判断才彻底解决了这个问题。另一个设计细节是suppress单独成字段不塞进duration。这两个概念经常被混淆duration是“触发前必须持续多久”suppress是“触发后多长时间内不再重复告警”。把两者分开规则配置才清晰。2.3 规则匹配的核心实现思路引擎执行一次匹配可以拆成三个步骤加载并校验规则、数据规整、条件评估。加载规则时不能只做JSON.parse还要对字段做合法性校验比如operator必须在枚举范围内、level必须是合法级别、duration必须大于0。否则一条错误配置可能导致整个引擎启动失败。数据规整这一步容易忽略不同采集Agent给的字段名可能不同单位也可能不一致。比如CPU使用率有的Agent给0.85有的给85如果没有在进引擎前统一规则阈值写成85就会出现一半机器一直告警、另一半永远不告警。条件评估是整个引擎的核心我重点讲讲时间窗口的实现。最简单的做法是每收到一条新数据就判断当前值是否满足阈值满足就告警。但这样会出很多误报比如CPU瞬时飙到90%又立刻掉下来其实不影响业务。真正可靠的告警标准应该是“在当前值满足阈值的同时过去一段时间内也持续满足”。实现时我维护了一个按秒滑动的指标缓冲每次新采样进来先入队再把超出duration范围的旧数据移出最后判断窗口内所有采样点是否全部满足条件。核心判断代码类似下面这样export function shouldTrigger(rule: Rule, buffer: MetricBuffer): boolean { const windowSamples buffer.lastSeconds(rule.duration); if (windowSamples.length 2) { return false; } return windowSamples.every((sample) compareByOp(rule.operator, sample.value, rule.threshold) ); }这里要求窗口内至少有两个采样点是为了防止引擎刚启动、只有一个孤点数据时就直接触发告警。实际使用中这个“至少两个点”的判断非常实用AI生成的第一版代码没有这段结果每次冷启动都会误报一轮。多规则同时匹配时我还定义了优先级规则level为critical的事件永远排在warning前面同一级别按触发时间倒序。这个排序逻辑看起来简单却直接影响了小程序的展示体验。告警事件里也保留了触发规则的原始快照方便后续回放问题。3. 用CodeArts智能体加速开发的实操记录3.1 从自然语言提示词到规则引擎骨架我在CodeArts IDE里新建了项目然后打开AI智能体面板第一次给的提示词很简单“用TypeScript写一个规则引擎支持阈值判断、时间窗口和告警输出。”生成的代码能用但和我想要的差很多没有规则校验时间窗口实现不完整全程用的是类似any的类型还引用了两个第三方库。这让我意识到提示词里必须写明运行环境、依赖约束和边界要求。第二次我调整了提示词你是资深运维系统架构师。请用TypeScript生成一个轻量级规则引擎模块运行在Node.js 18环境不依赖任何第三方库。输入为Rule[]和带时间戳的采样数据流输出为触发的告警事件。要求支持大于、小于、等于、不等于、属于集合五种比较运算支持duration秒内全部采样点满足才触发的持续判断规则字段需要做合法性校验并同时给出类型定义和Jest单元测试。这次生成的结果明显上了一个档次类型定义清晰MetricBuffer类也出来了甚至自动包含了sleep(0)这类边界处理的注释。当然它仍然有几个隐患MetricBuffer清理旧数据的算法写成了每次都整体过滤数据量大时性能会很差equal判断直接用对浮点阈值容易出现不该命中的情况。我在这个基础上继续追问“请优化MetricBuffer的清理逻辑使用环形队列而不是filter。”AI很快就改了这个“继续追问让AI迭代修改”的过程是这次实战里效率最高的部分。3.2 用智能体生成单元测试并反推bug修复规则引擎这类代码单测的价值极其明显。我让AI生成了一套单元测试覆盖的场景包括正常超过阈值、未超过阈值、单个采样点抖动、空数据、非法运算符、duration窗口内部分满足、duration为0、浮点相等比较等。测试跑下来果然抓到几个真实bug。第一个bug是in集合运算符写反了AI生成的代码判断的是“指标值不在集合内”就返回true语义完全反了。第二个bug是浮点相等阈值设置为0.85采样值是0.85000001用严格等于去判断就不通过改成基于EPSILON的近似比较就好了。第三个bug是非法运算符处理AI在默认分支直接返回false导致配置错误的规则静默失效而不是输出一条明显的配置错误日志。这个过程给我的启发是用AI写代码一定要配着让它写测试。因为测试会暴露出AI生成结果的语义偏差也能帮助自己真正理解引擎的行为。规则引擎里的边界条件太多了只要测试覆盖到位AI生成的不靠谱代码也能被快速兜住。这一轮下来我对最终代码的信心比之前手写脚本时要高很多。3.3 提交MR后的智能检视三个真实问题代码写得差不多后我把分支推送到CodeArts的代码托管并发起了MR。CodeArts的代码检视功能会在MR阶段对变更代码做增量扫描AI智能体会基于本次改动给出一批评论和建议。我没有做严格的召回率评测但实际过程里确确实实指出了三个值得处理的问题。第一个问题是duration为0时的行为没有定义。AI检视建议明确“0代表不检查持续时间只看当前值”而不是让代码进入一个奇怪的分支。第二个问题是规则排序不稳定多条规则同时触发时排序只按level字段未加二级排序条件同一批告警在不同时间可能顺序不同影响值班流的连续性。第三个问题是规则更新后旧配置缓存没有失效运行一段时间后修改规则文件引擎仍然用旧规则跑。这些大多是代码卫生层面容易漏掉的问题人也能看出来但让AI在MR阶段先扫一遍省了我不少自查时间。当然并不是所有AI建议都适合直接采纳。比如它建议我把规则引擎改成类单例模式但当前部署形态是每节点一个进程单例反而不好测试。所以我的原则是AI检视的结论当参考逐条确认后决定改还是不改。代码检视的最大价值不是“替人决定”而是“逼人重新思考一遍”。4. 运维巡检小程序的适配与联调4.1 小程序为什么不能直接运行引擎又该如何分工写小程序之前我认真考虑过“把规则引擎直接跑在小程序里”的方案然后果断放弃了。微信小程序运行在宿主的App环境里代码包有大小限制网络请求有域名白名单限制很多Node.js能力都用不了。更关键的是如果引擎逻辑全部跑到小程序里每次打开小程序都要重新加载、计算Rules更新和告警历史存储都变得很别扭。最终采用的拓扑是离线规则引擎跑在一个“本地运维盒子”里这台盒子可以是一台普通的Linux小主机部署在机房内网。小程序通过局域网HTTP请求访问引擎提供的接口引擎返回告警列表、指标实时值和规则版本。这样的好处是引擎持续运行即使没有打开小程序它也在后台默默判断告警小程序只是一个控制台和展示面板不需要承担计算压力。这个分工里还有一个细节引擎接口要设计成只暴露必要的操作比如“查询实时指标”“查询告警列表”“手动执行巡检”“更新规则包”。我不建议直接开一个SSH或者任意文件读写接口给小程序一旦小程序出问题暴露面越小越安全。4.2 页面结构和核心交互逻辑小程序端我做了三个主要页面巡检总览、告警列表、规则配置。巡检总览页面显示上次巡检时间、健康评分、关键指标的小卡片数据全部来自引擎的/api/overview接口。告警列表页用来展示当前未处理的告警按级别做颜色区分点击一条告警可以进入详情页里面展示指标历史曲线和建议处理方式。规则配置页默认是只读的展示当前生效规则及其版本管理员可以通过扫描二维码或者管理员密码解锁再导入新的规则包。手动执行巡检的交互是这样用户在首页点击“立即巡检”小程序调用/api/realtime/rules接口引擎收到请求后会主动触发一次数据采集立即执行一次规则匹配并把最新结果返回给小程序。这个设计能让值班同事在没有等待周期的情况下快速验证机器当前的状态。代码层面我用wx.request封装了请求超时时间设置成10秒避免弱网情况下长时间转圈。给一个请求示例wx.request({ url: http://192.168.1.20:8080/api/realtime/rules, timeout: 10000, success(res) { if (res.statusCode 200) { const alerts res.data.alerts; // 按 level 排序后更新页面 } else { wx.showToast({ title: 引擎无响应, icon: none }); } }, fail() { wx.showToast({ title: 网络异常, icon: none }); } });这里我踩过一个坑开发工具里默认打开了“不校验合法域名”请求很顺畅但真机上同样的请求直接被拦掉。后来在调试阶段用“真机调试 开启调试模式”临时解决正式使用则需要在小程序后台配置request合法域名或者把请求地址收敛到固定的内网网关域名。4.3 数据落地、历史记录与轮转策略告警数据不能只停留在内存里否则重启就全丢了。我在引擎侧用了SQLite作为存储表结构尽量简单先是alerts表字段包括id、ruleId、level、metric、value、status、created_at、resolved_at。status字段记录告警状态active表示未恢复resolved表示已恢复acknowledged表示值班人员已确认。历史数据如果不清理时间长了SQLite文件会越涨越大。我设置了一个简单的轮转策略保留最近30天的告警记录超过30天被移动到一个归档表再更早的数据直接按天删除。小程序拉取告警时使用分页接口一次只取20条避免一次拉几千条把浏览器和小程序拖垮。这里有一个实际体会告警列表中不要把所有原始规则配置都展示出来否则界面密密麻麻只需展示规则名称、级别、指标值、触发时间这几个核心字段原始配置放到详情页通过“查看规则”入口再看。5. 常见问题与排查技巧实录5.1 规则“不触发”的排查清单规则引擎上线后遇到最多的反馈就是“这条规则为什么不告警”。很多情况下不是引擎坏了而是配置和实际数据对不上。我整理了一张排查清单按顺序排查基本能定位90%的问题排查项说明指标名是否一致采集数据里的字段名和rule里metric字段要严格一致注意大小写单位是否统一CPU分数是0-1还是0-100磁盘是百分比还是字节数duration窗口是否配置过长采集周期远大于duration时窗口内样本数达不到2个enabled是否为true规则关闭状态下不会参与计算采样时间是否合法Agent机器时区与引擎时区不一致导致lastSeconds取不到数据引擎日志里规则是否加载成功规则文件语法错误时引擎通常会整批跳过排查时不要只盯规则文件先去引擎日志里看“规则加载数”和“指标命中数”这两个统计。如果指标命中数为0说明数据规整环节就有问题比如单位没换算、字段名不一致如果命中数正常但不告警再检查时间窗口和相关配置。把“加载”和“匹配”两步分开统计是快速定位的关键。5.2 告警风暴与抑制策略状态机是基本功刚开始上线的时候告警风暴差点把我自己淹没。一条磁盘告警每30秒触发一次每次触发都会调接口推消息值班手机一晚上收到一百多条。后来我加了抑制逻辑核心是三态状态机normal表示正常alerting表示告警中recovered表示已恢复。只有从normal进入alerting时才推送紧急通知在alerting状态持续期间即使规则继续命中也只更新事件时间不重复发消息当规则不再命中进入recovered状态发一条“已恢复”消息然后回到normal。实现时只需要维护一个MapruleId, lastState每次评估结束后更新状态。加上suppress字段还能进一步控制告警频率。比如某条规则刚触发了一次那在一个小时内即使触发条件再次满足也不重复告警。这个机制对于运维巡检小程序特别重要因为告警列表页面会实时显示活跃告警数量如果不抑制页面上的数字会不断跳动让人分不清是不是新问题。5.3 小程序真机联调的坑小程序联调阶段我主要踩了三个坑。第一个是域名白名单。开发工具里即使勾选了“不校验合法域名”真机仍然校验局域网IP默认不在白名单里。我的解决方式是在开发阶段用微信开发者工具的真机调试模式然后临时在小程序后台把内网网关域名加进白名单正式环境则要求现场工程师通过运维盒子反代一个域名出来。第二个坑是本地存储限制。小程序wx.setStorage单个key最多存1MB总存储上限10MB如果把告警历史全存进去很容易触发写入失败。所以我只缓存最近20条展示数据和必要的登录状态其余数据全部走接口。第三个坑是弱网表现。机房内网偶尔也会抖动wx.request默认超时时间在部分版本表现不稳定。我手动把超时设置为10秒同时在请求失败时加入重试按钮而不是自动无脑重试。手动重试的好处是不会在弱网时叠加请求造成雪崩。这些细节做出来后现场同事反馈小程序的体验稳定了很多。6. 实战体验与后续可扩展方向6.1 AI智能体这轮实战给我的真实体会整个项目下来我对CodeArts的AI智能体有了比较真实的感知。它最擅长的是“输入输出边界清晰、逻辑重复度高”的模块规则引擎正好就是这种情况。只要我把约束条件说清楚比如离线、无第三方依赖、需要校验、需要测试它生成的第一版代码就能达到可运行的水平后续再通过提问和单测逐步修正比从零手写省了至少三分之一的时间。它还有一个很有价值的点帮我把边界条件重新过了一遍。比如浮点比较、duration为0、空数据、集合运算语义这些地方人写的时候很容易一带而过但AI生成的测试会专门覆盖。我自己写单元测试经常“报喜不报忧”让AI生成反而更容易暴露反直觉的case。当然它也不是万能的业务语义相关的设计它很难帮忙比如“为什么监控数据盘而不是根分区”“告警级别该不该有确认流程”这些还是得靠人来决策。我的建议是用AI智能体做代码生成一定要把它当作结对编程的队友而不是代写工具。每次生成后先读一遍主干再让它补测试再提交MR走检视这个流程能把AI的收益最大化。6.2 后续扩展从热更新到巡检报告这个项目目前的状态是可以稳定运行但我脑子里已经有了一长串后续想做的事。首先是规则热更新现在更新规则包需要重启引擎进程我希望后续能监听规则文件的变化解析通过后自动加载不中断在线巡检。其次是可视化规则编辑现场运维不一定熟悉JSON如果能做一个表单化页面把阈值、运算符、时间窗口都变成下拉框和输入框出错的概率会低很多。再往后是上报和报告断网期间产生的告警希望在网络恢复后批量上报到云监控中心同时每周自动生成一份巡检报告把各节点的告警数量和恢复时长汇总成PDF直接邮件发送给团队。规则包本身也可以用CodeArts的流水线来管理把规则配置做成一个独立Git仓库每次改规则都走代码评审发布时打Tag并生成配置包再分发到各个边缘节点。这样告警规则和业务代码一样有了完整的变更链以后追溯问题会方便得多。最后分享一个我自己养成的习惯每次拿到AI生成的代码我不会直接提交而是先通读主干逻辑再让AI生成对应的单元测试跑通之后才提交MR走检视。这个方法在这个离线规则引擎项目里帮我省下了大量时间也把漏报这类问题提前拦在了测试阶段。如果你也在做运维巡检、告警规则这一类的系统建议从一条最简单的CPU阈值规则开始把“采集-加载-匹配-告警”这条路完整走通再回头处理边界场景比一开始就追求功能大而全要实际得多。
返回列表