自动化系统本身,也需要被自动化运维。
如果写自动化的人天天在手动运维自己的自动化系统,这件事本身就挺讽刺的。

我们把浏览器池、调度中心、DAG编排、规则引擎、代理管理、配置中心十几个模块全搞上线了,系统越来越复杂。然后我们发现一个尴尬的事实:我们花了大半年做自动化,结果自己每天还要花两三个小时手动运维这套自动化系统。

查看哪台执行机磁盘快满了、手动清理僵尸进程、重启卡死的Worker、检查为什么某个店铺的任务队列又堆积了、排查代理出口今天怎么又慢了——这些事和传统运维没什么区别,只是被运维的对象从业务系统变成了自动化系统本身。

系统规模小的时候,手工运维还能应付。但当我们把执行节点扩到8台、店铺数突破100、每天跑上千个自动化任务的时候,手工运维彻底崩了。告警邮件一天收几百封,淹没了真正重要的信息。经常是小问题拖着没发现,拖成了大故障。

这篇文章讲我们怎么把运维自动化的思想应用在自动化系统自己身上,建立起一套巡检、诊断、修复的运维闭环。


一、运维对象不止是机器

传统运维盯的是CPU、内存、磁盘、网络。这些当然要盯,但对我们这套店群自动化系统来说,真正要命的运维对象远不止这些。

我们梳理出了五类必须主动运维的对象:

执行节点:机器层面的健康度——CPU、内存、磁盘、网络、系统时间、关键进程存活。

浏览器池:实例数量、空闲率、分配失败次数、脏实例比例、端口占用状态。

任务队列:各优先级队列长度、任务等待时间、失败重试率、死信堆积。

代理网络:每条代理的连通性、延迟、出口IP一致性、带宽余量。

店铺环境:登录态有效性、环境指纹完整性、代理绑定正确性、user-data-dir磁盘占用。

这五类对象的状态不是孤立的,它们之间有复杂的因果链。比如执行机磁盘满了,会导致浏览器无法写缓存,进而导致页面加载失败,表现为任务失败率飙升。如果运维只看“任务失败率”这个表象,就一直在表层绕圈子,找不到磁盘这个根因。

运维自动化的第一步,不是写脚本,而是把运维对象和它们的依赖关系建模清楚。


二、主动巡检:在问题变成故障之前发现它

被动响应告警是最低效的运维方式。告警意味着问题已经严重到触发了阈值,影响了业务。我们的目标是让大部分问题在触发告警之前就被巡检发现并处理。

我们实现了一个分级巡检调度器,按照不同的时间周期和优先级,调度各种巡检任务。

高频巡检(每30秒)

  • 各执行节点心跳
  • 浏览器池空闲实例数
  • P0任务队列长度

中频巡检(每5分钟)

  • 代理连通性和出口IP校验
  • 任务成功率按店铺统计
  • 浏览器实例健康检查(进程存活、调试端口响应)

低频巡检(每小时)

  • 磁盘空间和user-data-dir大小
  • 配置一致性校验(节点配置与基线对比)
  • 登录态批量探测

日巡检(每天凌晨)

  • 数据完整性校验(采集量与历史基线对比)
  • 代理流量和费用统计
  • 审计日志完整性检查

巡检任务本身也是通过调度中心来执行的。每个巡检任务是一个特殊的自动化任务,由调度中心分发到各执行节点,执行结果上报到运维数据库。

class PatrolScheduler:
    def __init__(self, scheduler_client, patrol_definitions):
        self.scheduler = scheduler_client
        self.definitions = patrol_definitions

    def tick(self):
        now = time.time()
        for patrol in self.definitions:
            if now - patrol.last_run >= patrol.interval:
                self.scheduler.submit(patrol.task_definition)
                patrol.last_run = now

巡检任务不是只查不治。每个巡检项都定义了异常判定条件自动修复动作。比如“浏览器池空闲实例数为0”这个异常,关联的自动修复动作是“触发实例池扩容”或“回收僵尸实例”。巡检发现问题后,优先尝试自动修复,修复失败再升级为告警。


三、诊断引擎:从现象到根因

巡检发现异常,但异常的根因是什么?磁盘空间不足可能是日志文件过大,也可能是某个店铺的user-data-dir异常膨胀。直接清理日志能临时释放空间,但如果根因是后者,过两天又会满。

我们做了一个轻量的诊断引擎,它维护了一张“现象-可能根因-验证方式”的知识图谱。

现象: 浏览器实例分配失败率突增
├── 可能根因1: 端口耗尽
│   验证方式: 检查端口占用数是否接近上限
│   修复动作: 回收僵尸实例,释放端口
├── 可能根因2: 内存不足
│   验证方式: 检查系统内存使用率
│   修复动作: 强制触发V8 GC,回收脏实例
├── 可能根因3: 代理故障
│   验证方式: 检查最近代理巡检结果
│   修复动作: 触发代理切换
└── 可能根因4: 浏览器进程僵死
    验证方式: 检查实例进程状态和调试端口响应
    修复动作: 强制kill并重建实例

诊断引擎按照优先级逐一验证可能根因,找到匹配的根因后,调用对应的修复动作。如果所有预定义根因都不匹配,引擎生成一份详细的诊断报告(包含相关指标快照和日志片段),推送告警让人工介入。

诊断引擎的知识图谱是可扩展的。每次线上出了一个新的根因类型,复盘后我们会把它添加到图谱里。运行半年后,图谱积累了40+条诊断规则,覆盖了我们遇到的绝大部分异常模式。


四、自愈动作的层级与安全边界

自动修复不是什么都该自动做。有些修复是无风险的(比如清理临时文件、重启卡死的Worker),有些是中风险的(比如重建浏览器实例、切换代理),有些是绝对禁止自动执行的(比如批量修改店铺配置、重启整台执行机)。

我们定义了自愈动作的三级安全边界:

L1 - 无风险自愈:自动执行,事后记录日志。包括:回收僵尸浏览器实例、清理过期日志和临时文件、重置卡死的Worker线程、刷新过期的配置缓存。

L2 - 有风险自愈:自动执行,但会生成一条操作记录推送到运维看板,如果30分钟内同类型自愈触发超过3次,升级为告警。包括:重建浏览器实例、切换备用代理、重启执行节点上的影刀客户端。

L3 - 禁止自愈:只告警,不自动执行。包括:修改店铺环境绑定、执行数据修复脚本、重启调度中心主进程。

这个安全分层让自愈既能解决大部分问题,又不会因为过度“自主决策”而闯祸。


五、从告警风暴到智能收敛

监控告警那篇文章里我们提过告警分级和抑制,但运行一段时间后告警仍然偏多。特别是在故障连锁反应时——一个代理断了,导致10个店铺的任务失败,又导致队列积压,又导致内存飙高——瞬间产生几十条告警,运维根本看不清根因在哪儿。

我们进一步做了告警收敛和根因推断

告警引擎不再一条一条单独推送,而是维护一个时间窗口(5分钟)内的告警聚合视图。窗口内所有告警被归并到同一个“告警事件”里,并尝试推断根因告警。

推断逻辑基于告警之间的因果链依赖图。代理断了会导致“任务失败率上升”和“浏览器实例分配异常”,后两者是代理断了的症状,不是根因。收敛引擎识别到这种因果链后,把症状级告警折叠,只突出根因告警,并在事件描述里说明影响范围。

运维收到的通知从“25条告警”变成“1个事件:代理px_045故障,影响12个店铺,正在自动切换中”。信息密度大幅提升,决策时间大幅缩短。


六、运维看板与健康评分

我们建了一个综合运维看板,不是给机器看的,是给人看的。看板核心是一个系统健康评分,由五类运维对象的健康度加权计算得出。

每个对象都有一个子评分:

  • 执行节点:CPU/内存/磁盘的综合利用率偏离度
  • 浏览器池:空闲率、分配成功率
  • 任务队列:P0/P1任务等待时间中位数
  • 代理网络:在线率和延迟达标率
  • 店铺环境:登录态有效率和任务成功率

总评分如果低于80分,看板变黄;低于60分,变红并触发P0告警。

健康评分不只是展示,它还是自动运维决策的依据。比如评分低于80时,自动暂停所有P3级别的离线任务,释放资源给高优先级任务;评分低于60时,停止新任务提交,全力消化存量积压,直到评分恢复。


七、自动运维的反面案例与教训

自动运维不是银弹,我们也踩过坑。

有一次日巡检脚本检测到某个执行节点的磁盘使用率超过85%,自动触发了日志清理。清理逻辑写得太激进,把当天还在写入的日志文件也给删了,导致Filebeat断点错乱,丢失了半天的审计日志。修复后我们给清理逻辑加了安全保护:只清理超过24小时的滚动日志文件,当天文件无论如何不动。

还有一次,浏览器池的空闲实例巡检发现空闲数为0,自动触发扩容,新建了5个实例。但这5个实例的user-data-dir是从模板复制的,模板里残留了一个测试用的代理配置,导致这5个实例全部使用了错误代理。几个店铺的出口IP因此混乱,触发了平台的安全验证。从那以后,扩容逻辑改为必须从环境工厂走标准初始化流程,而不是简单的目录复制。

每一个自动修复动作,都需要在生产环境的混乱中被反复锤炼,才能真正变得可靠。
自动化运维不是写好脚本就不管了,它需要和业务系统一样被持续迭代和验证。


八、自动化运维的量化收益

这套运维体系上线后,我们统计了前后对比:

  • 平均故障发现时间从23分钟降到4分钟
  • 平均故障恢复时间从35分钟降到8分钟(含人工介入的场景)
  • 60%的异常通过自愈自动恢复,运维人员无需介入
  • 告警数量从日均200+条降到日均15条左右
  • 夜间被叫醒处理故障的次数从每周3~4次降到每月1次

更重要的是,团队的工作模式变了。以前运维是“事件驱动”的——不出事不关注,出事了一窝蜂上。现在变成了“巡检驱动”——每天打开看板扫一眼健康评分,评分正常就安心做开发,评分异常就深挖巡检报告。焦虑感大幅降低。


九、继续演进的方向

当前运维体系最明显的短板是预测能力不足。巡检和诊断都是“已经发生异常”之后的反应,我们还没有做到“预测即将发生异常”的水平。

比如磁盘空间,现在是用了85%才告警,但如果我们能根据历史增长速率预测3天后会满,就可以提前清理,完全避免告警。代理质量也是,如果能根据延迟的上升趋势提前切换,就能在代理彻底断开之前完成平滑过渡。

另一个方向是把运维知识图谱和规则引擎结合起来,让诊断逻辑本身也变成可配置的规则,而不是硬编码在Python脚本里。这样运维团队可以自己扩展诊断规则,不需要工程师介入。

运维自动化的终极目标,不是让系统永远不出问题,而是让问题在真正产生影响之前就被消解于无形。
这是一个永无止境的追求。

作者:林焱
一个终于不用凌晨三点被叫起来修系统的工程师

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐