自动化系统最危险的时刻,不是它报错的那一秒。
而是它已经错了三天,却没有任何人知道。
前两篇文章我们把浏览器实例池和店铺环境隔离聊透了,系统终于能在几十个店铺的规模下稳定跑起来。但上线第二周,现实就给了我们一巴掌:一个TEMU采集流程因为页面改版,连续两天在同一个元素定位上失败,任务队列里积压了上千条失败记录。而我们还浑然不觉,直到运营同事来问“为什么这两天数据没更新”。
那次之后我们定了一条铁律:没有监控的自动化,就是在裸奔。
这篇文章专门讲我们怎么给影刀RPA执行集群搭一套完整的监控、告警与异常自愈体系,让系统真正做到无人值守也能及时发现病灶,并尝试自我修复。
一、监控对象:从“机器死了没”到“业务对不
很多团队做监控,第一反应是盯着服务器CPU、内存、磁盘。这些当然重要,但对一个店群自动化系统来说,真正的业务问题往往不会直接反映在机器负载上。
我们需要监控的东西,可以分成四层:
第一层:基础设施层
执行机在线状态、CPU、内存、磁盘、网络连通性。这类指标通过常规的Prometheus Exporter或者Windows性能计数器就能拿到。
第二层:浏览器池层
池内实例总数、空闲实例数、分配失败次数、实例销毁重建速率、端口占用情况。这些是我们自己定义的业务指标,反映池子是否健康。
第三层:任务执行层
任务提交速率、任务完成速率、队列堆积长度、任务平均耗时、任务失败率(按店铺、按流程类型拆分)。这是调度层的核心业务指标。
第四层:业务结果层
这是最关键也最容易漏掉的一层。比如“采集到的订单数是否接近零”、“上货数量是否异常下降”、“消息回复成功率是否突然掉到50%以下”。这些指标必须和正常业务基线做对比,才能发现那种“流程明明在跑,但产出全是错的”的隐蔽故障。
机器没挂、任务没失败、流程跑完了,不等于业务正常。
业务结果异常,才是最终极的告警触发条件。
二、日志架构:结构化与集中化
我们要求所有执行节点、调度中心、浏览器池管理器输出的日志都是结构化的JSON,并且包含统一的字段规范。
一条标准的任务执行日志长这样:
{
"timestamp": "2026-05-18T10:23:45.123Z",
"node_id": "executor-03",
"task_id": "abc-123",
"shop_id": "temu_045",
"flow_name": "order_collect",
"status": "failed",
"error_code": "ELEMENT_NOT_FOUND",
"error_detail": "Selector .order-list-item not found at step 3",
"duration_ms": 23450,
"browser_port": 9225,
"retry_count": 1
}
日志通过Filebeat实时采集到Elasticsearch,在Kibana上做可视化和搜索。这让我们能快速回答任何关于“某个店铺在某个时间段发生了什么”的问题。
但我们很快发现一个问题:影刀自身的日志几乎是黑盒。 影刀流程内部如果抛了一个未捕获异常,命令行输出里只给一个笼统的退出码,根本没有上下文。
为此我们做了一个重要改造:所有影刀流程的起始和结束,都必须在调度层记录边界日志,并且在流程的关键步骤主动输出自定义日志(通过影刀的“写日志”指令或者直接调用Python插件写文件)。这样即使影刀内部挂了,我们也能根据边界日志推断出大致死在哪一步。
三、告警规则设计:不是报警越多越好
刚开始我们什么都想告警,浏览器池水位低于5个就告、单个任务失败就告、CPU超过70%就告。结果告警邮件一天能收200封,很快就变成了所有人自动归档的垃圾邮件。
后来我们定了三级告警策略:
一级告警(紧急):系统不可用,需要立刻人工介入。
- 调度中心服务挂掉
- 所有执行机同时掉线
- 任务队列堆积超过2000条且持续增长
- 浏览器池连续5分钟无可分配实例
这类告警通过企业微信、电话通知,并且如果15分钟未处理会自动升级通知范围。
二级告警(警告):局部功能受损,需关注。
- 单个执行机掉线
- 某个店铺连续失败超过5次
- 代理出口批量失效
- 磁盘空间低于10%
这类告警通过企业微信消息推送,工作时间处理即可。
三级告警(提示):性能波动或业务异常,不必立即处理。
- 任务平均耗时超过基线20%
- 某个流程类型的失败率突破3%
- 浏览器实例回收速率异常升高
这类告警只推送到运维看板上,不主动骚扰人,供回顾时分析。
我们还专门做了一个“告警抑制”逻辑:如果同一个店铺同一个错误码在5分钟内触发了10次告警,只会发第一条,后面的合并到摘要里延迟通知。避免告警风暴。
四、异常自愈:能自动恢复的,就别叫人起床
监控告警只是发现问题,真正让系统变强的是它能自己处理一部分问题。
我们梳理出三类可自愈的异常:
4.1 进程级异常
比如浏览器崩溃、影刀执行器僵死、临时网络抖动导致的任务失败。
自愈策略:在调度Worker里增加一个内层的自动重试逻辑。任务失败后,根据错误类型决定是否重试。如果是元素超时、网络超时这类临时故障,最多重试2次,每次间隔递增(5秒、15秒)。超过重试上限或者遇到明确不可重试的错误(如登录过期),任务转人工队列。
def run_with_retry(task, max_retries=2):
last_exc = None
for attempt in range(max_retries + 1):
try:
execute_task(task)
return
except RetryableError as e:
last_exc = e
logger.warning(f"Task {task.task_id} retryable error, attempt {attempt+1}")
time.sleep(5 * (attempt + 1))
except NonRetryableError as e:
raise # 直接抛出,不重试
raise MaxRetryExceededError(last_exc)
4.2 环境级异常
比如浏览器实例健康检查失败、代理不通、用户数据目录损坏。
自愈策略:浏览器池的健康巡检线程一旦发现实例不可用,立即将其标记为“不可用”并尝试销毁重建。代理不通的问题通过一个独立的代理检测脚本(在实例启动前跑一次curl测试)来提前发现,直接换备用代理。
4.3 流程级异常
比如页面改版导致元素定位失败,这是最难自愈的一类。我们目前在尝试的方法是将这类失败自动截图并记录DOM快照,然后由人工或未来的AI分析模块来生成修复补丁。目前还无法做到全自动修复,但至少让定位问题的成本降到最低。
五、任务队列积压的自愈闭环
队列积压是我们最怕的一种故障模式。一个流程挂了,任务不停往队列里塞,消费者处理不过来,队列长度指数级增长,最终把Redis内存撑爆,然后所有服务跟着连锁崩溃。
我们做的防护手段有三层:
第一层:生产端限流。 调度中心下发任务前,先检查队列长度。如果超过阈值,暂停该店铺的新任务提交,并触发告警。
第二层:消费者端动态扩容。 执行节点池有空闲容量时,调度中心会拉取积压任务加速消费。不过这个受限于机器数量,我们目前还是手动加节点,自动扩容需要容器化支持,后续再做。
第三层:队列尾部丢弃+回溯。 在极端情况下(比如队列已经堆了上万条),我们会启用应急模式:保留最新的一部分任务,丢弃最旧的重复任务(如同店铺同类型的重复采集任务),并记录丢弃清单,事后通过补跑机制回溯。这个逻辑在Redis里用Lua脚本原子化执行,避免竞态。
六、看板设计:让系统状态一目了然
我们用Kibana做了三块看板,对应不同角色。
运维看板:展示所有执行机的健康状态、浏览器池水位、队列堆积、告警趋势。这是一个大屏,挂在办公室墙上,运维扫一眼就知道现在系统是否正常。
业务看板:按店铺维度展示成功率、耗时、采集量趋势。业务运营同学看这个就知道今天自动化产出如何。
调试看板:工程师专用,可以按任务ID、店铺ID、时间段检索原始日志和截图,快速定位失败原因。
这三块看板极大降低了沟通成本。以前运营老是问“今天数据怎么没出来”,现在他们自己先看业务看板,确认是系统问题还是流程问题,再决定找谁。
七、自愈策略的安全边界
在做自动恢复的时候,有一条线我们始终不敢越:涉及金钱、订单状态变更的操作,绝对不能自动重试。
比如改价、报活动、确认发货,这些操作一旦出现异常,只允许挂起人工处理,绝不允许自动回滚或重试。因为自动重试可能导致重复扣款、价格多次覆盖等致命后果。
我们在任务定义里加了一个 safety_level 字段:
safe:可自动重试,失败后自愈caution:可自动重试一次,失败后人工介入critical:绝不自动重试,直接挂起并电话告警
所有流程上线前都必须标注安全等级,调度器在执行时严格遵守。
八、演练:把故障常态化
监控和自愈体系上线之后,我们并没有直接高枕无忧。我们每两周会做一次“混沌工程演练”——主动注入故障,看系统反应是否符合预期。
比如:
- 随机kill掉一个执行机上的浏览器实例
- 拔掉一台执行机的网线
- 向任务队列注入一批必然失败的脏任务
- 修改某个店铺的代理配置为无效地址
每次演练都会暴露一堆问题。比如有一次我们手动kill掉一个浏览器进程,池子巡检线程正常发现了异常并重建,但重建后没有恢复 env.json 指纹文件——因为重建逻辑调错了初始化函数。这种边界bug在正常运行时根本碰不到,只有故意制造混乱才能揪出来。
让系统在可控的混乱中成长,比在生产环境里被动崩溃要好得多。
九、这套体系最终给团队带来了什么
有数字能说话:接入这套监控自愈体系后,我们的MTTD(平均故障发现时间)从原本的“运营反馈才知道”的数小时,缩短到了分钟级。MTTR(平均故障恢复时间)从人工登录服务器手动杀进程、重启流程的30分钟以上,压缩到大部分问题在5分钟内自动恢复。
更重要的是,团队的心态变了。以前大家时不时就要瞄一眼服务器,生怕出问题;现在即使半夜收到告警,也会先看一眼自愈状态,多数情况已经自己处理掉了,可以翻个身继续睡。
十、未完的话
监控和自愈是一个永远做不完的工程。我们目前最头疼的问题有两个:一是流程失败截图如何自动分析并给出修复建议,二是当业务逻辑本身出问题(比如平台改了规则)时,怎么在自愈框架里优雅地引入人工决策节点,而不是完全靠人去排查。这些是我们接下来要啃的骨头。
自动化系统成熟度的标志,不是它能跑多少流程。
而是出问题时,它能用多快的速度告诉你,并尝试把自己修好。
作者:林焱
一个持续在自动化工程一线填坑的工程师
