凌晨被告警叫醒后,我发现熵增先于事故发生  

目录
  1. 凌晨的空白不是故障,而是系统终于承认自己偏离了
  2. 我最初以为问题出在一次发布,后来才看见它早已开始漂移
  3. 真正的修复不是把这次超时填上,而是重新确认系统为何存在

凌晨的空白不是故障,而是系统终于承认自己偏离了

凌晨两点十七分,手机在枕头边震动,把我从浅睡里拽出来。屏幕上不是客户消息,而是一条告警:某条依赖服务持续失败,失败原因却只有“连接超时”。我第一反应是网络抖动,披上外套便打开远程终端,想找昨晚刚发布的配置。服务没有崩,也没有堆积错误;更奇怪的是,它几乎不接请求,安静得像一条已经下班却仍占着门牌的流水线。

我先查进程,再查端口,最后去看依赖配置。整个过程花了二十多分钟,真正让我停下来的不是某个参数写错,而是一个此前一直被忽略的事实:这项服务已经从“处理请求”变成了“拒绝请求,但拒绝得很礼貌”。没有请求,也没有错误。它没有明确告诉我哪里坏了,只是通过超时让我不断回来检查。

凌晨两点十七分的终端里,最醒目的不是红色错误,而是连续几行空白:没有请求,也没有错误。那一刻我突然意识到,故障不一定先以异常的形式出现。

我以前把服务状态理解成一条简单的线:正常、处理中、异常。现在我更愿意把它看成一组假设:它假设上游会持续发送某种格式的请求,假设证书和环境变量长期有效,假设某项依赖不会悄悄改变默认行为。只要这些假设还成立,进程活着、日志干净、监控没有红灯,它就会显得“正常”。可一旦现实偏离假设,系统并不会立刻鸣叫;它可能只是越来越慢、越来越沉默,最后把偏差包装成一次无法解释的超时。

这就是我现在对熵增的理解:熵增不是混乱突然降临,而是一个系统长期没有清理自身假设,逐渐偏离设计初衷的日常过程。

我最初以为问题出在一次发布,后来才看见它早已开始漂移

我先查了当天的变更记录。凌晨前确实有一次发布,范围不大,只更新了一个共享配置。我盯着提交差异看,觉得每个字段都合理,甚至能解释为什么请求没有按照预期进入下游。于是我把注意力放回发布流程,验证回滚、检查实例、观察流量。那天晚上没有找到确定的根因。

第二天早上,我们重新对照设计和现状,才发现配置本身没有写错。变化来自更早以前:一个默认值在几个月前被覆盖,团队后来修改了调用方,却没有恢复原来的约定;另一项依赖升级后,对空输入的处理方式改变了;还有一个监控指标一直只统计“已建立的连接”,却没有统计“收到但未处理的请求”。每个改动单独看都像合理决策,合在一起,却让服务越来越不像当初被设计的样子。

这次经历让我想起自己过去写过的《从零构建 Hermes Agent 记忆系统——memory-filtration-layer 迭代手记》(2026年)。那时我以为,只要把逻辑收拢到统一入口,系统就会更可控。后来我才明白,入口可以统一,隐含前提却会散落在调用方、配置、环境和监控里。代码没有变得更乱,假设却越来越没人完整掌握。

我们逐条回看变更记录时,没有找到那个“按下按钮就损坏”的瞬间。系统不是在一夜之间变坏,而是一个月接一个月地偏离自己曾经依赖的条件。

熵增在这里不是物理学意义上的神秘力量,而是维护债的具体形态:没人知道谁还依赖旧行为,没人确认默认配置是否仍有意义,没人保证监控仍在测量真正关心的事情。它不制造戏剧性,它只积累差异。

我过去更相信显式错误。错误码、失败日志、红色告警至少给出了行动方向;这种“没有任何请求但也没有任何错误”的状态,反而更令人不安。现在我的判断变了:越重要的系统,越不能只依赖异常暴露问题;正常状态本身也需要被持续验证。

真正的修复不是把这次超时填上,而是重新确认系统为何存在

最后我们没有继续追那一次发布。我们先回到最初的设计文档,问了一个当时显得多余的问题:这项服务究竟要保证什么?是转发消息,还是保证消息一定被处理?调用方真正依赖的是超时时间,还是请求顺序?下游返回空结果时,上游应该失败,还是可以把它当成无事发生?

答案逐项浮出来后,修复反而变得简单。我们补了“无请求但实例可用”和“收到请求但未处理”的观测,恢复了几个被覆盖的默认值,为依赖升级后的行为加了明确测试。更重要的是,我们在发布流程里加了一道检查:凡是曾经改变过服务契约的依赖,升级时必须重新验证调用方假设。

这不是因为我突然崇尚文档。文档本身也会腐烂。真正有用的是把关键假设变成可以执行的检查:输入为空时怎么办,依赖升级后返回什么,连续空闲多久需要告警。只有这样,假设才不会只存在于某个已经离职同事的脑子里。

那次故障最后不是靠“找到罪魁祸首”结束的,而是靠我们把一句模糊的话——“它应该正常工作”——改写成几条能够被机器反驳的条件。

但我也没有把这件事包装得太漂亮。新增检查会增加发布成本,有些假设甚至无法完全自动化。更现实的办法,是为核心路径保留少量人工确认,其余部分靠测试和观测覆盖。系统不会因此回到绝对有序的状态,我们能做的只是让偏移更早显形,让它不必等到凌晨两点才通过一次沉默的失败通知我。

过去的我总把事故理解为某个具体动作造成的断裂。现在我认为,许多事故只是长期失配终于被某个偶发事件照亮。那次告警真正叫醒我的,不只是服务异常,而是一个更不舒服的问题:我们究竟有多久没有验证过,系统还是按照我们以为的方式存在?

47.6k
豫ICP备2023032045号-1