从Inform到Operate:基于Mission调度的云成本巡检闭环实践
2026/9/16 22:44:56 网站建设 项目流程

大部分团队的云成本巡检,停留在“Inform”这一层:系统每天扫一遍资源,发现几个闲置实例,弹一条告警,然后……就没有然后了。告警发出去之后,真正去处理的可能不到三成,剩下的七成要么没人认领,要么下次巡检时又被筛出来,周而复始。我今天想聊的这套机制,目标是把巡检从“通知”推到“运营”,让告警直接驱动资源回收、降配、退订这些动作,而把人工留给真正需要判断的场景。整个闭环的编排,由一个自研的 Mission 调度模块负责——它就是整个巡检机制的“发令枪”和“监工”。

1. 巡检这件事,为什么容易“只报告不解决”

成本巡检在很多团队里是个“有也行,没有也行”的活。为什么会这样?因为巡检最原始的形态就是写几个脚本,调用云厂商的查询接口,把数据拉下来算一遍,然后输出一张 Excel 或者推送几条消息。这种模式刚上线时效果很明显——第一次扫出几十台闲置机器,老板觉得这系统真有价值。但运行几个月后,大家就开始麻木了。

1.1 成本失控的几个典型场景

我先列举我在实际巡检中最常遇到的几类问题,这些基本覆盖了大部分云上成本浪费。

第一类是纯粹的闲置资源。开发环境一台 32C64G 的机器,连续 15 天 CPU 使用率没超过 3%,内存占用不到 10%。这种机器往往是人走了流程没走完,项目下线了但机器没同步清理。更典型的是 NAT 网关、负载均衡这类附属资源,它们不直接产生计算账单,但每个月光服务费加流量费累计起来非常可观。

第二类是低利用率资源。不能说完全没用,但配置远高于实际需求。比如一个内网管理系统,两台 8C16G 的实例做双机,日常 QPS 不到 20,CPU 长期在 5% 到 8% 之间徘徊。这类资源不能直接释放,但降配甚至合并到一台机器是完全可行的。

第三类是规格膨胀。业务初期买了 64G 内存的机器,后来业务量反而下降了,但没人去降配。还有一类常见的是给存储卷买了远超实际使用的容量,比如挂载了一个 500G 的高效云盘,实际只用了 30G。

第四类是流量与带宽异常。带宽按固定规格购买,但实际峰值一直用不满;或者某个实例出方向流量突然翻倍,导致流量费暴涨。前者是浪费,后者是异常,都需要巡检能分辨出来。

这几类场景有一个共同点:用一句话就能判断要做什么,资源能不能释放、能不能降配、是不是异常。但就是没有一套机制把“判断”变为“执行”。

1.2 Inform 阶段的三个死穴

“查出来有什么用呢?”——这是我经常听到的一句话。之前纯 Inform 的巡检机制,也就是只管发告警、出报表的模式,至少要回答三个问题:数据准不准?谁来处置?处置结果有没有反馈?

第一个死穴是告警疲劳。巡检规则一多,每天产生的告警条目动辄几十条。人的注意力是有限的,连续看一周后,看到一个“存在闲置资源”的卡片完全无感。最后的结果就是告警被群消息折叠,出现的频率越高,被处理的概率越低。

第二个死穴是没有处置闭环。告警里写了“某实例 CPU 使用率低于 5%,请检查是否需要释放”,但没有任何后续动作的追踪。这个实例是已经被处理了,还是仍然闲置?报告里看不出来,下次巡检还会再报一次。等于把一个判断题做成了一道永远重复的选择题。

第三个死穴是策略无法沉淀。哪些规则精确、哪些规则误报多,依赖人的记忆。巡检系统只负责算,不负责“改进”。比如你根据几次误报调整了阈值,但调完没有记录,过几个月同事接手,又调回去了。

这三个死穴的根源在于:巡检链路只覆盖到“消息通知”这一环,后面从决策到执行都是断的。要解决它,不能只靠加规则,而是要把调度和执行也纳入这条链路。这就是我下文要说的 Mission 调度要干的事。

2. 机制设计的核心思路:从 Inform 到 Operate

我理解很多团队把成本巡检做成了“报表工具”,而一个好的巡检机制,本质应该是一个“运营工具”。差别在哪?报表工具的输出是信息,运营工具的输出是动作。

所以在设计这套机制时,我给自己定了一条原则:每一条巡检洞察,都必须映射到一个明确的处置动作上。这条原则直接决定了后面所有的架构决策。

2.1 一条巡检结果,必须对应一个处置动作

我按照这个思路重新梳理了巡检结果的分类。拿一台低利用率实例来说,传统巡检输出的是:“实例 i-xxxx 过去 7 天 CPU 平均 3%,请关注。”新机制输出的应该是:“实例 i-xxxx 过去 7 天 CPU 平均 3%,满足‘低利用率实例’规则,建议降配到 4C8G,预计每月节省 420 元,操作安全等级:中,可自动执行。”同样的数据源,输出格式一改,整个处置链路就完全不一样了。

要让每条巡检结果都能映射到动作,需要把“分析”和“决策”做两层拆分。分析层只判断事实:这个实例利用率是多少,是否符合某个规则的特征。决策层则负责判断怎么做:能不能动、怎么动、谁来批准、何时执行。

这里有个很容易踩的坑:把决策逻辑和巡检逻辑写在一起。比如在巡检脚本里直接写上“如果 CPU 小于 5% 就调用释放接口”,这看起来很高效,但实际上非常危险。因为巡检脚本每天都在跑,它没有处理各种边界情况,比如这台机器是不是被某个临时任务占用着。我的建议始终是,巡检只负责“标记”,决策层负责“处置”,两层用数据表或消息队列解耦。

2.2 Mission 调度的定位与职责

在明确了巡检和处置分开之后,剩下的问题是:谁来把“标记”变成“处置”?谁来保证整个环节按时、按序、可重试?这就是 Mission 调度的位置。

Mission 在整套机制里承担三个职责:

第一,定时触发巡检任务。它按照配置好的 cron 表达式,到点把采集任务、分析任务、决策任务依次调度起来。这就是最基础的“任务编排”。

第二,管理任务间的依赖关系。采集成功之后才能做分析,分析有结果之后决策层才能拿到数据。Mission 通过任务状态和依赖规则,保证它们按正确的顺序执行,而不是靠一个脚本从头跑到尾。

第三,提供执行能力和审计能力。巡检分析完,如果命中可自动执行的规则,Mission 负责调用对应的云 API 来执行操作,并且把操作记录落库,形成一条完整的审计链路。

我会在第四节详细说 Mission 的实现细节,这里先强调它的边界:它不管业务逻辑,只负责“调度”和“执行”,业务逻辑全部放在巡检规则和处置动作的插件化配置里。

2.3 闭环流程的完整链路

从整体上看,这套机制运行起来之后是这样的:

每天凌晨 2 点,Mission 里的全量巡检任务被触发。先把云上的实例、存储卷、带宽、负载均衡、NAT 网关等资源清单拉一遍,同时拉取前一天的账单明细。数据落库后,分析任务开始跑,把每条资源喂给预定义的规则集,输出命中结果。那些命中“可自动执行”规则的资源,被决策层放入执行队列,按预设的执行策略进行操作。执行完成后,验证任务再跑一次,确认操作生效,比如实例确实降配了、快照确实删除了。

最后生成一份巡检日报,里面不只写“发现了什么问题”,还写“自动处理了什么”“节省了多少钱”“哪些需要人工确认”。日报推送到 IM 群的时候,大家看到的是结果,而不是一串等待处理的待办。这个设计上的转变,直接改变了成本巡检在团队里的定位——它从“找问题的”变成了“解决问题的”。

这个闭环的价值在于,巡检不再是一次性动作,而是一个可持续运转的机制。只要调度器在跑、规则在更新,成本的浪费就会持续被识别、被消除、被验证。

3. 巡检规则与成本分析的关键细节

闭环设计好之后,下一个问题就是:规则怎么定,才算准?我自己写规则踩过很多坑,这里把关键细节展开说说。

3.1 数据源与采集口径的选择

成本巡检的数据源一般有三类。第一类是资源清单接口,返回当前账号下有哪些实例、存储卷、IP、负载均衡等,以及它们的状态和规格。第二类是监控指标接口,提供 CPU、内存、流量、IOPS 这些时序数据。第三类是账单明细,包含每小时或每天的费用明细,以及产品类型、地域、标签等维度信息。

这三类数据必须交叉使用,不能只看一类。比如只看资源清单,你会发现一堆“看起来处于运行中”的实例,但不知道它们实际负载情况;只看监控指标,又可能漏掉那些没有监控数据但仍在计费的附属资源。最典型的坑是:判断一个实例是否闲置,如果只凭 CPU 使用率,很容易漏掉那些 CPU 本来就没压力的内存型应用,所以需要同时看内存、IOPS、网络流量等多维指标。

还有一个关键点是采集口径的时间对齐。云厂商的账单数据普遍存在 T+1 延迟,甚至个别产品 T+2。如果巡检任务在凌晨 0 点跑,拉到的可能是前天甚至更早的数据;如果白天跑,当天账又没出。我实际用的方案是:凌晨 2 点跑一次全量,中午 12 点跑一次增量,增量主要用于覆盖前一天账单的修正数据。这样可以有效避免因为数据延迟导致的漏检。

3.2 常用的巡检规则与阈值设计

规则是巡检机制的“大脑”,规则准不准直接决定整个系统可信不可信。下面是我目前在用的几套规则,参数都是经过几轮调优后的结果:

规则判断条件建议动作安全等级
闲置弹性 IP公网出流量 7 天为 0,且无绑定解绑并释放低风险,可自动执行
低利用率实例CPU 均值 < 5% 且内存 < 10%,持续 7 天降配或迁移中风险,需谨慎自动执行
过期快照创建时间超过 30 天,且不是最近 3 份之一删除低风险,可自动执行
空负载均衡后端服务器数为 0,持续 7 天释放低风险,可自动执行
带宽超配近 30 天出方向峰值 < 购买带宽 20%下调带宽档位低风险,可自动执行
跨地域流量激增单日流量费环比增长 > 100%告警并生成分析报告高风险,仅通知

关于阈值,有几个经验可以分享。判断“低利用率”如果用 7 天 CPU 均值小于 5%,在业务稳定的系统上很准,但对深夜无流量的国内业务会误报,所以要加“工作时间段窗口”的概念,只统计 9 点到 18 点的均值。判断快照是否该删,别只看年龄,还要看它是不是某个自定义镜像或系统镜像的依赖;最稳妥的做法是先标记“候选删除”,保留 7 天冷静期再真正删除。

另一点很重要:规则的输出不能只给“是/否”,还要带上支撑数据。命中“低利用率实例”规则时,报告中要能直接看到近 7 天的 CPU 趋势、内存趋势、出方向流量趋势。这样无论是人工复核还是自动执行的审计,都有据可查。

3.3 误报治理与例外清单

没有规则是一上来就准的,误报是常态,关键是建立误报治理的方法。我在实践中主要做了三件事。

第一,建立例外清单。某些业务季末月结、或者固定的数据批处理任务,会在月末或每周固定时间打满 CPU,这类资源要加入例外清单,规则直接跳过。清单要支持按标签匹配、按实例 ID 匹配,也要支持有效期。比如“该实例在营销活动期间不巡检”,有效期 15 天,到期自动失效。

第二,告警收敛。同一资源连续多天命中同一条规则时,只在第 1 天和第 7 天告警,中间的天数静默。避免“狼来了”效应。

第三,建立反馈通道。巡检报告里每条结果都支持标记“误报”并填写原因。这些反馈会回写到一个样本表,定期用来调优规则阈值。我把这个表叫“规则评测样本集”,每个季度跑一次,看哪些规则精确率低于 80%,就针对性调整或下线。

误报治理这件事看起来不起眼,实际上决定了巡检机制能不能长期运营下去。原因很简单:用户对系统的信任,是被一次次误报消耗掉的。一旦群里的告警被集体屏蔽,再好的技术方案都是白搭。

4. Mission 调度的实现细节

现在讲回 Mission 调度本身。这是整套机制里技术含量最高的部分,也是保证“可持续运行”的底座。

4.1 任务模型设计

我把一个完整巡检流程拆成三类子任务:采集任务、分析任务、执行任务。这三类统称为一个 Mission。Mission 定义里面包含的信息有:任务的唯一标识、执行计划(cron 表达式)、依赖关系、超时时间、重试策略、执行时使用的凭证标识。

下面是一个 Mission 定义的简化示例,我习惯用 YAML 来管理:

mission: name: daily-cost-inspect schedule: "0 2 * * *" # 每天凌晨 2 点 timeout: 3600 retry: max_attempts: 3 backoff: "5m,30m,2h" # 指数退避 steps: - name: collect-resources type: collect depends_on: [] - name: analyze-cost type: analyze depends_on: [collect-resources] - name: decide-operations type: decide depends_on: [analyze-cost] - name: execute-operations type: operate depends_on: [decide-operations]

这里每个 step 之间通过 depends_on 建立依赖,Mission 控制器只会把“依赖已满足”的任务投递到执行队列。从这套模型里可以看出来,Mission 没有把逻辑写死在代码里,而是通过配置组装流程,这也是它能够复用的原因。

4.2 调度策略与依赖管理

调度策略核心是三件事:定时触发、依赖满足与超时处理。

定时触发使用 cron 表达式。实际配置中,我把任务分为两类:全量巡检每天跑一次;增量巡检每 4 小时跑一次。全量巡检负责把资源清单和账单重新梳理一遍,增量巡检只关注是否有新产生的资源,以及有没有突发的异常指标。全量跑太久会挤占增量任务,所以我在调度器里加了任务互斥锁:同一类型的 Mission 同时只能有一个实例在执行,避免执行重叠。

依赖管理上,Mission 用“前置依赖成功数”来判断是否放行。比如 analyze-cost 依赖 collect-resources,那么只有 collect-resources 标记为 succeeded 后,analyze-cost 才会被投递。如果前置任务失败,后置任务不会启动,整个 Mission 会进入 Retrying 状态,按配置的重试策略重跑。

这里有个容易被忽略的细节:任务超时。云厂商接口偶尔会卡住,如果采集任务没有超时控制,整个 Mission 会一直卡在 running 状态。我在设计里给每个任务强制加了 timeout,默认 30 分钟,超时后任务被标记为 failed,Mission 进入重试流程。实测下来,这个机制能挡住绝大多数“莫名卡死”的情况。

4.3 幂等控制与状态回溯

调度系统做自动执行,最怕的是执行动作重复。比如同一个闲置 IP,第一次巡检把它解绑了,但释放动作因为网络超时报了失败,重试时发现这个 IP 已经不存在了,再调一次释放接口可能就报错甚至影响其他资源。所以幂等是必须的。

我的做法是给每个 Mission 实例生成全局唯一的 run_id,这个 run_id 贯穿整个流程。在操作执行前先查审计表,如果发现该 run_id 已经执行过同一操作,就直接跳过。同时,所有操作在真正调用云 API 之前,都要先做一次前置确认,比如“实例还存在吗”“实例规格是否已经变化”,前置确认不通过就不执行,这样即使状态信息有延迟,也不会做无效操作。

状态回溯方面,我保留了每个 Mission run 的完整事件日志。从任务启动、采集完成、分析命中、操作执行,到执行结果的每一步,都写入一张 event_log 表。之后排查问题或者复盘时,直接根据 run_id 查整条链路的日志,效率非常高。这张表也是我后面做成本节省量统计的基础数据源。

4.4 失败重试与告警升级

最后说处理失败。调度系统不可能永远成功,关键是失败后怎么处理。Mission 里每个任务都有独立的失败处理策略,默认重试 3 次,使用指数退避(5 分钟、30 分钟、2 小时)。如果 3 次重试后仍然失败,Mission 会被标记为 failed,并触发告警升级流程。

告警升级的逻辑是这样的:先把失败信息推送给 Mission 的负责人,如果 2 小时内没有得到确认,再推送给上层值班组。这里的关键是“升级”而不是“群发”。刚开始我用的方案是一失败就把告警发到所有相关群,结果往往是很多人看到但没人认领。改成单点负责人 + 超时升级之后,处理效率反而高了很多。

另外还有一个实操经验:重试时一定要区分错误类型。如果是因为凭证过期、权限不足这类配置错误,重试再多也没用,应该第一时间告警让人介入。如果是因为网络超时、接口限流这类瞬时错误,重试才有意义。我在代码里把错误分成了可重试和不可重试两类,不可重试的错误直接跳过重试并告警。

5. 实操落地:部署一套成本巡检与 Mission 调度

前面讲的都是设计,这一节直接讲怎么落地。我把这套机制跑在一个独立的运维区域里,使用容器部署,下面按步骤说明。

5.1 环境准备与凭证配置

我用的部署环境是一台 4C8G 的云服务器,组件包括:MySQL(存储规则、任务状态、审计日志)、Redis(任务队列)、Mission Controller 和 Mission Worker。Controller 负责解析 Mission 定义并管理调度状态,Worker 负责真正执行具体的采集、分析、操作任务。两者都可以通过容器镜像部署,用 docker compose 起起来比较省事。

关键点是云厂商凭证的配置。我强烈建议使用子账号凭证,而不是主账号密钥。这个子账号只需要授予巡检所需的只读权限,以及指定资源操作的权限。比如要支持自动删除快照,那就只授予“删除快照”和“查询快照列表”这几个 Action;要支持降配实例,只授予“查询实例”和“修改实例规格”。权限边界越窄,自动执行的风险越低。

还有一个容易忽略的点:凭证要加密存储,并通过环境变量或密管系统注入到容器。别把凭证明文写在配置文件里,更别提交到代码仓库。这块出过不少事故,我是深有体会。

5.2 巡检规则文件的配置示例

规则配置我放在一个 rules.yaml 文件里,加载进系统时校验格式。下面是两个规则的示例:

rules: - name: idle_eip_release description: "闲置弹性 IP 释放" resource_type: eip condition: outbound_bytes_7d: { operator: "sum", max: 1024 } binding: { operator: "eq", value: false } action: type: release approval: auto cooldown_days: 7 - name: low_utilization_instance description: "低利用率实例降配" resource_type: instance condition: cpu_avg_7d: { operator: "lt", value: 5, window: "9-18" } mem_avg_7d: { operator: "lt", value: 10, window: "9-18" } running_days: { operator: "gte", value: 30 } action: type: resize approval: manual target_spec: "auto"

看上面第二个规则,我加了 running_days 大于等于 30 天的条件,这是为了过滤掉刚创建不久、还在压测或预热阶段的实例。target_spec 设置为 auto,表示让系统根据资源近 30 天的峰值自动推荐一个规格,而不是写死某个目标规格。

5.3 注册 Mission 并调试调度

规则配好后,通过管理接口注册 Mission。系统会校验 Mission 定义的格式、规则文件是否存在、子任务依赖是否成环。校验通过后,Mission 会出现在调度列表里,可以手动触发一次,也可以等待 cron 到点触发。

初次调试时,我一般先手动触发一次,并把 execution_mode 设为 dry_run。dry_run 模式下,分析照常跑,命中照常记录,但不会真正执行操作。查看报告确认命中结果符合预期后,再把模式切换为 real_execute。这个开关是整套机制的“保险丝”,建议一直保留,紧急情况下可以一键把所有操作类任务下掉。

5.4 自动执行与后端验证

当 Mission 运行到 operate 阶段时,Worker 会调用云 API 执行操作。每个操作在真正执行前都走一遍前置确认流程:查资源状态、查操作是否已在审计表中存在、查规则是否仍然命中。都通过之后才执行。

执行完成后,验证任务会再次查询资源状态,确认操作是否真正生效。比如删除快照操作,验证任务会再查一次快照列表,确认目标快照已不在列表中。验证结果、操作耗时、失败原因都会写入 event_log。如果验证失败,会按照 4.4 节的策略进入重试或告警升级流程。

整个系统跑起来之后,我每天只需要做一件事:花几分钟看巡检日报,确认哪些资源被自动处理了,哪些需要人工审批。大部分时间,日报上的“自动处理”一栏就是当天的全部工作。

6. 常见问题与排查实录

这部分记录我在实际运行中遇到的最典型问题,按问题现象、排查过程、解决方案的方式写。

6.1 采集数据延迟导致漏检

现象:某天巡检报告里,前一天新开通的一批实例完全没有出现。

排查过程:我先查事件日志,发现采集任务正常执行,返回的资源清单数量也对。再对比云控制台上的实际资源,发现新实例是前一天下午创建的,而 Mission 在凌晨 2 点拉到的账单和资源数据里,部分产品的状态信息还停留在前天的缓存上。

解决方案:把全量巡检时间从凌晨 0 点调整到凌晨 2 点,给数据同步留出足够时间。同时增加 12 点的增量巡检,专门覆盖前一天的修正数据。另外在采集任务内部加了一个“数据新鲜度检查”:如果拉到的账单数据最终更新时间早于当前时间 12 小时,就标记该批次数据为 stale,分析任务会绕开这些数据,避免基于旧数据做判断。

6.2 误报太多导致告警被屏蔽

现象:上线第一周,群里告警非常多,很多根本不值得处理。第二周开始,群里基本没人讨论告警了。

排查过程:我逐条看了告警,发现大头来自两条规则。一条是低利用率实例,把周末没人访问的测试环境实例都标成了低利用率;另一条是闲置弹性 IP,把那些虽然没绑定但在走“预释放流程”的 IP 都标成了闲置。

解决方案:低利用率规则增加了工作时间窗口,只统计 9 点到 18 点的指标;闲置 IP 规则增加了一个 exclude_status 参数,跳过处于“预释放”状态的 IP。同期把告警收敛策略打开,同一资源同一规则 7 天内只报一次。改完一周后,告警量下降了约 70%,且每个告警都有人响应。

6.3 Mission 重复执行导致操作重复

现象:某天手动触发了一个维护任务,同时又撞上 cron 定时触发,结果同一批快照的删除操作被执行了两次。还好删除接口是幂等的,第二次调用报了个“目标不存在”,没有造成实际损失,但审计日志里出现了两条执行记录。

排查过程:查调度日志发现,手动触发时没有检查当前是否有同类型 Mission 实例在运行,导致两个实例并发执行了。

解决方案:在 Mission 控制器里加了互斥锁,同一 Mission 名称下同时只允许一个运行中的实例。同时把操作前置确认做实:任何操作在执行前都要查一次目标资源是否存在,如果资源已经不存在,就不再调用云 API,只记录一次 skip 事件。从那以后,这个坑再也没踩到。

6.4 权限不足导致执行失败

现象:自动降配操作在执行阶段大面积失败,错误信息显示“无权限”。

排查过程:核查后发现,凭证本身有权限,但 Worker 调用的是另一个项目的接口,而该接口要求必须在那个项目下额外绑定权限。也就是说,权限不是加在用户上的,还要加在项目维度上。

解决方案:重新梳理了权限模型,在云厂商的项目维度上补齐了 Worker 需要的权限策略,并为不同项目分别建立了一组凭证。配置落实后,我又补了一条规范:权限变更时必须执行一遍 Mission 的 dry_run 加单条执行测试,验证通过后才能恢复自动执行。

最后聊点个人体会。做这套机制最让我意外的不是技术难度,而是运营节奏的变化。以前每天的工作是“看告警、转派、催人处理”,现在变成了“看报告、审异常、调规则”。省下来的时间可以用来做更重要的预算规划和架构优化。如果你也正被一堆成本告警淹没,我的建议是先别急着加告警规则,而是想一想:这些告警背后的动作是什么?谁能执行?怎么验证?想清楚了,把从 Inform 到 Operate 这条链路补上,你会很快看到不同。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询