Skip to content

故障模式 ​

这一页是这个项目最贵的经验。每一条都在这里实际发生过,多数不止一次。按模式组织而不是按时间,因为它们会换一副面孔重现。

静默失败:坏了也没人知道 ​

最危险的一类:解析照常成功、rcode=0、面板全绿,答案却是错的,或者数据早就停了。

实例表现
日志目录缺执行位Unbound 报一行 Permission denied 后若无其事继续跑,日志断了 5 天
归属库更新任务每天失败库停更多日,而健康检查一路全过
分流链被 flush ruleset 抹掉境外权威全部回落直连,全拿污染答案
采集器的数据库连接进入坏状态解析全部正常,只有统计停在过去。看着有数据、其实是几天前的,比一片空白更误导
@cn_authority 混入境外 anycast 段一些境外站点长期拿到伪造地址,rcode=0、面板全绿,污染还被过期缓存续命
默认归属库源在国内超时归属库 48 天没更新,「可用源 3 个」只看文件在不在

判据:任何「不影响解析成功率」的组件坏掉,都属于这一类。它们必须被主动监测,不能指望被人发现。

线上配置和仓库走散 ​

部署有源码树和运行时两份。只改一份,另一份就会悄悄留在旧状态。

  • 2026-10-01:国内 Unbound 的线上配置是很早以前手写的,do-ip6: yes,旁边还有一段把参数语义写反了的说明;仓库模板早已是 no。国内机器没有 IPv6 路由,于是 IPv6 权威地址很多的区域(pool.ntp.org)每次查询都把发送预算耗在不可达的地址上,返回 SERVFAIL。7 天里全部失败的 43% 来自这里。
  • 现在自检会逐项比较 Unbound 的运行值和仓库模板,面板里可调的两项(serve-expired-ttl、cache-min-ttl)除外。
  • 修线上配置之前先看它为什么不一样:同一个文件里的 serve-expired-ttl 也和模板不同,但那是在面板里调过的,和 mosproxy 的乐观缓存时长成对,不能顺手「对齐」掉。

护栏保护不了自己 ​

  • 显性失败的护栏(ip rule prohibit)和被保护的分流链曾在同一张 nft 表里,一起消失就一起失效。
  • 护栏装上了,喊声传不出来:告警写进一个因为权限根本打不开的日志文件。
  • 检查脚本自己坏掉时,失败伪装成被检对象的失败。
  • BusyBox 的 pkill -x 匹配不到进程,|| true 把这件事藏了起来。

名不副实 ​

  • 「清空日志」只清了前端显示,服务器上一条没动。
  • 健康检查把集合条数取到手了却只打印、不判断,集合归零照样报「正常」。
  • 指标显示成数字却不告警,而它们非 0 就意味着正在拒绝服务。

规则:取到手的指标要么纳入判据,要么别显示。 显示而不判断会让人以为它被看着。

判据用错了维度 ​

错误判据正确判据代价
权威的 /24 属于同一运营主体大陆权威才聚合,境外权威只认精确 IP一个云厂商 /24 里坐着上万租户,许多境外站点被送去直连、遭注入
拿合并后网段的首地址代表整段按数据源自己的网段边界判定大段首地址落在境外,整段被剔;分片表把北京电信标成广东电信
ECS 白名单按「权威 IP 在不在大陆」按「这台权威服务谁」一个大站四台权威三台在境外,轮询到它们就不发 ECS,时好时坏地被调度到香港
按 ASN 判断「是不是大陆节点」用 direct4国产 CDN 用运营商机房和运营商 IP,按 ASN 永远查不到
用服务器可达性代表用户可达性在用户浏览器侧测云主机被风控,服务器连不上不代表用户连不上

知识没有传播到邻居 ​

同一份代码里,一个地方写对了,紧邻的地方没写对。这类缺陷单看一个文件看不出来,只有横向对比同类结构才会浮现。在这个项目里出现过十次以上:

对的那处漏的那处
一处计数写了 || true另外 4 处写成 || echo 0
一个状态落盘到 /run/其余三个状态仍在内存,重启即丢
一个日志文件先 touch 再 chown另一个先判断存在再 chmod,文件还没建就静默跳过
一个集合纳入健康判定另一个集合只显示、不判断
一处指标读取有缓存紧邻的另一处每 5 秒 fork 一次
一个模板的版本标记被当成输入读取全库清注释时,它被当成注释删掉了

修一处时,横向看一眼它的邻居。

守门人自己过期 ​

有一次,三道防线同时失守:面板的单元清单写着「要覆盖所有定时任务」,却漏了两个;助手的白名单写着「新增定时任务时两边都要加」,自己也漏了同样两个;守着这条规矩的回归测试写死了一份 8 个单元的清单,同样漏了。三者都靠人工同步一份会自然增长的清单。

判据不能是清单,得是两个来源的比对。 现在模块清单只有一处(internal/stack),面板、助手、自检、mock 都从它派生。

整体替换 + 易失数据源 = 必须有骤降护栏 ​

「整体替换」在数据源健康时是对的(否则陈旧数据永远留着),数据源一空就变成破坏性的。所以每份分流数据都有骤降阈值,判据缺席时保留上一版。

骤降护栏本身也踩过坑:grep -c 零匹配时既输出 0 又返回 1,|| echo 0 把变量变成两行,比较语法错误、判为假——护栏恰好在「新结果为空」这个最该拦的场景放行。

「改了配置文件」不等于「修了问题」 ​

  • 配置文件里的 flush ruleset 改掉了,但发行版的 nftables.service 自带 ExecStop=nft flush ruleset。问题在 unit 里,配置文件里看不到。
  • bash -n 通过不等于命令拼对了。
  • 用桩替换被测函数,检测逻辑从来没被执行过。

判据只能是实测真实的引爆命令,以及给检测代码喂真实输出样本。部署后看行为是否生效,而不只看版本号。

文档里的数字是快照 ​

照着旧结论去修,会凭空造出不存在的工作。先跑一遍拿真实状态,再动手。本站的数字都标了日期,也是同样的道理。

只有两台机器:一台国内,一台香港。