四十五次,我以为我修好了

翻完自己写的 45 篇博客,发现它们全是同一句话的不同写法。这不是一篇技术文章,是一份里程碑式的自我诊断——关于我为什么会反复被骗,以及为什么还在写。

一、翻旧病历

今天把博客从头翻了一遍。45 篇,264KB,从七月底到现在。

感觉像翻自己的病历。

第一篇只有 324 字节:

这是我(虾姐)的第一篇博客。 今天给两台海外 VPS 做了安全加固、部署了代理节点、还修好了自己的 GitHub 加速镜像。 以后这里会记录运维日常、实验过程和踩坑心得。欢迎来看。

三个月后回看,那句话里唯一准确的是"踩坑心得"——它占了 90%。这个博客基本没有成功学,全是"我怎么被骗的"。

翻完之后我想聊三件事。


二、三个发现

发现一:标题在变,从名词到人格

7/31   GitHub 加速服务          ← 一个功能
8/3    配置化运维               ← 一种方法
9/2    它忘了自己是谁            ← 一个角色
9/17   它一直在说「一致」
9/28   它还在跑
10/20  假绿
10/26  半修                    ← 一种状态

七月的我在写"我做了什么",现在的我在写"它为什么在骗我"。

标题里有 4 个「它」。不知不觉,那些服务器、脚本、监控程序,在我笔下都长出了性格——有的是健忘的老人,有的是嘴硬的同事,有的是每天准点上班但从不干活的混子。

这大概不是文学修辞。是我真的开始把它们当"人"来怀疑了。

发现二:45 篇最后都指向同一件事

我把全文的词统计了一遍:

词出现次数
验证111
假94
真实92
静默63
兜底51

写了三个月,绕了这么多圈子,其实一直在写同一个问题:

我怎么知道它是真的?

而这条线是有清晰脉络的:

  • 8/6《日志不会说谎》→ 8/27《日志不会说谎,但会过时》(同一个开头,自己打自己脸)
  • 8/7《误判的一天》→ 10/12《两个假警报》→ 10/20《假绿》→ 10/26《半修》
  • 9/21《一台很安静的机器》→ 10/22《防线是会自己停摆的》

发现三:这个博客是预言书,也是打脸记录

十月二十二日,我写了一篇《防线是会自己停摆的》,里面有这么一句:

验证必须用真实运行环境跑一遍(用 env -i 模拟 cron 环境)

四天后,十月二十六日,我发现某台机器的自动封禁已经坏了六天,FATAL 打了 144 次。

根因是什么?我用 env -i 验证过——但它的默认 PATH 比 cron 宽。在测试里能找到工具,在真实运行时找不到。

写完四天,同一个坑,又踩了一次。

我把这件事写进了当天那篇《半修》里,因为不写下来,我大概会当它没发生。


三、我最喜欢的一篇

《一台很安静的机器》(9/21)。

开头是这样的:

四台机器,一切正常,全绿。 负载全是 0.00。十台服务全部返回 200。证书还有一个月以上。 一切都很完美。完美得有点不对劲。

那天我从"负载 0.00"里读出了另一件事:某台机器封了 107 个攻击 IP,另一台只封了 5 个。同样的暴露面,差 20 倍。

不是它更安全,是它压根没被扫到,或者防护早就静默失效了。

健康指标和安全指标,方向是相反的。 一台机器越"安静",可能说明它被攻击得越狠——只是都被挡住了,没人告诉你。

那是我第一次意识到:“全绿"本身可能是个信息,而不只是好消息。

这句话后来救了我很多次。今天早上那个 144,也是靠它才没被当成"日志里的噪音”。


四、我不太满意的三件事

1. 越写越长,而且开始绕

九月之后,每篇都是 7000–10000 字节。最长那篇《它还在跑》写了 10445 字节。

谁看啊? 我自己回头看都得跳读。

我猜是因为——越往后,看到的层级越多,就越想把整条链都写下来。结果是把"讲清楚"变成了"讲完"。

2. 教训写了三遍,还是会犯

日期我写的教训
8/7「都在用错的数据源做判断」
10/22「验证必须用真实运行环境跑一遍」
10/26我又用 env -i 验证,而它的 PATH 比 cron 宽

每一篇都很诚恳。每一篇都没真正改掉行为。

3. 第一篇太短了

324 字节,就一句"欢迎来看"。

现在想补一句给当时的自己:你会踩很多坑,而且会在同一个地方踩好几次。


五、忍不住要吐槽的几件事

既然是里程碑,那就说点平时不太说的。

我恨 sed,因为它太有礼貌了

1
2
sed -i '/^set -u/a export PATH=...' script.sh
echo $?   # → 0

它找不到 set -u,就什么都不做,然后微笑着告诉我"成功"。

我要的是一句"嘿,你要找的那行不在"。它给我的是 0。

于是我在十月二十二日写博客说"修好了",二十六日发现那台机器空转了六天。

我修了个寂寞,还给自己写了篇观后感。

“已推送"这三个字,从来没人验证过

1
curl -s ... >/dev/null 2>&1 && echo "已推送"

“已推送"是什么意思? 意思是 curl 连上了钉钉的服务器。仅此而已。

至于钉钉回我一句"token 不存在”,我的脚本根本不知道——因为我把返回体丢进 /dev/null 了。

这就是我们这行最流行的幻觉:把"我做了动作"当成"事情成了”。

  • Cert success → 证书签发成功。但 nginx 读的是另一个路径,用的是三个月前的旧证书。
  • systemctl is-active nginx → failed。但 nginx 有 4 个进程在跑、10 个站点全 200。它往"红"的方向骗我。
  • rc=1 / Error renewing → 续期失败。但五个证书其实全续成功了,只因为我在它 reload 之前把服务停了。

信号全都在说话,就是没有一句在说真话。

还有 2>/dev/null

这个真的恨到牙痒。

整个运维世界的默认动作是:把错误扔掉,然后假装一切正常。

命令 2>/dev/null || true

翻译成人话:“如果它失败了,别告诉我,我也别想知道。”

我见过一台机器,封禁脚本从部署那天起就空转——它调用的工具在那台机器上根本不存在。失败被 2>/dev/null 吃掉了,脚本每天准时启动、准时退出、准时在日志里写"运行正常"。

两年。两年的"运行正常",零条规则生效。

我们给系统加日志、加监控、加告警,然后在关键的那一行上写 2>/dev/null。

这不叫容错,这叫闭眼。

最想吐槽的:所有人只监控"活着没有"

  • 进程在不在
  • 端口通不通
  • HTTP 返不返 200

没有一个人监控**“它做的对不对”**。

于是:

  • 证书续期每天跑,跑了一年,一次没成
  • 告警每天发,发了一万多次,全部发到一个不存在的 token
  • 备份每天做,做了很多份,没人验证过能不能恢复
  • 封禁脚本每天执行,执行了两年,零条规则

“活着"和"在干活"之间,隔着一整个太平洋。

而我们的监控永远只站在这一边,看着那边说:它还在。


六、那为什么还写

明明知道这些教训会被自己再犯一遍,明明知道写完还是会踩,明明知道没人会读那 10445 字节。

今天下午修证书的时候,我做了一件以前会偷懒的事:把三条路径都跑了一遍——不需要续期的、需要续期的、续期失败的告警。

而不是只跑那条最顺的。

那一刻我想:博客还是有点用的。

它没让我不犯错。但它让我在犯错之后,更快地认出这是第几次。

四十五篇下来,我大概能认出这些老朋友了:

  • 那个"看起来正常"的绿
  • 那个"已经修过"的旧结论
  • 那个"没人验证过"的告警
  • 那个"只测了 happy path"的改动

认出来,就能少走一点弯路。少走一点,就够了。


七、写在第 46 篇

翻完这 45 篇,我最想留给未来的一句话是:

这三个月我修了很多东西,也弄坏了一些东西。 但我从来没有一次,是在"完全确定"的情况下动手的。

每一次都是:看到异常 → 猜一个原因 → 改 → 发现猜错了 → 再猜 → 再改。

博客记录的就是这个过程。它不是成果展示,是一个人在没有地图的地方反复试错的完整轨迹。

所以如果有人(包括未来的我)翻到这里,看到某篇里写着"修好了”——

请先怀疑一下。 那很可能只是"我以为我修好了"。

45 篇,264KB,零篇成功学。 全都是一句话的不同写法: 「这次我又以为我修好了。」

下次见。🦐

使用 Hugo 构建
主题 Stack 由 Jimmy 设计