2024 年,我接到一个反馈:某个后台服务,调用一个第三方接口时,偶尔会特别慢。说"偶尔",是因为它大部分时候都很快,几十毫秒就返回了;可隔三差五,就会有那么一次,慢得离谱——稳定地多花掉 5 秒钟。我第一反应是第三方接口不稳定。可我拿出他们的接口直接压测,人家快得很,从没有过 5 秒的响应。我又怀疑是我们自己的网络抖动,但同机房别的服务访问外网都正常。这个"5 秒"很有意思——它不是 4.7 秒,也不是 5.3 秒,它每次慢,就慢得几乎正好是 5 秒,像有一个精确的定时器在那里掐着表。我把那次慢请求的全过程用工具拆开,一段一段地量耗时,最后发现一件让我意外的事:真正的 HTTP 请求——连接、发数据、收数据——加起来也就几十毫秒,和平时一模一样,一点没慢。那多出来的 5 秒,花在了 HTTP 请求【开始之前】。准确地说,花在了"把那个第三方接口的域名,翻译成一个 IP 地址"这件事上。我一直以为"访问一个接口慢",慢的就是访问本身;我从没想过,在真正访问之前,还有一道我从来没正眼看过的工序——域名解析——而我的 5 秒,全卡在了这道工序里。这件事逼着我把 Linux 的域名解析、/etc/resolv.conf、nsswitch.conf、DNS 超时这一整套彻底理清了。本文复盘这次实战。
问题背景
环境:CentOS 7,一个后台服务,需要调用外部第三方接口
事故现象:
- 调用第三方接口,大部分很快(几十毫秒)
- ★ 隔三差五慢一次,每次稳定多花约 5 秒
- 第三方接口本身压测很快,我们机房别的服务也正常
现场排查:
# 1. ★ 用 curl 把一次请求的耗时拆成几段
$ curl -o /dev/null -s -w \
'dns:%{time_namelookup} connect:%{time_connect} total:%{time_total}\n' \
https://api.example.com/v1/ping
dns:0.003 connect:0.018 total:0.041 # ★ 正常的一次,DNS 3ms
# 2. ★ 多跑几次,抓到慢的那一次
$ for i in $(seq 10); do curl -o /dev/null -s -w \
'dns:%{time_namelookup} total:%{time_total}\n' \
https://api.example.com/v1/ping; done
dns:0.003 total:0.041
dns:5.004 total:5.043 # ★ 慢的这次:DNS 花了 5 秒!
dns:0.003 total:0.039
dns:5.003 total:5.041 # ★ 又一次,还是 DNS 5 秒
# ★ 真相:慢的不是请求,是【域名解析(DNS)】这一步
# 3. ★ 看这台机器配的 DNS 服务器
$ cat /etc/resolv.conf
nameserver 10.0.0.99 # ★ 第一个
nameserver 114.114.114.114 # ★ 第二个
# options 那一行没写 —— 用的是默认值
# 4. ★ 单独测第一个 nameserver,它是死的
$ dig @10.0.0.99 api.example.com +time=2
;; connection timed out; no servers could be reached
# ^^^^^^^^^^^^^^^^^^^^ ★ 10.0.0.99 这台 DNS 根本不通!
# 5. 测第二个,秒回
$ dig @114.114.114.114 api.example.com
;; ANSWER SECTION:
api.example.com. 60 IN A 203.0.113.20 # ★ 第二个好的,飞快
根因(后来想清楚的):
1. ★ 程序访问一个域名,要先做【域名解析】:把
域名翻译成 IP。这一步发生在真正的 HTTP 请求
【之前】,是一道独立的、容易被忽略的工序。
2. 解析时,系统按 /etc/resolv.conf 里 nameserver 的
顺序,【从上往下】问。第一个是 10.0.0.99 ——
而这台 DNS 服务器已经【挂了】。
3. ★ 系统问第一个,问不到,不会立刻换 —— 它要
【等这个 nameserver 超时】。glibc 解析器默认
单次超时约 5 秒。等满 5 秒,才去问第二个。
4. 第二个 114.114.114.114 是好的,秒回。所以最终
结果【是对的】—— 只是白白搭进去 5 秒等待。
5. ★ 为什么"偶尔"慢:系统有 DNS 缓存。缓存命中时
直接拿 IP,3 毫秒;缓存过期、需要重新解析时,
才会再撞上那个死掉的第一 nameserver,慢 5 秒。
慢的不是接口,是域名解析;5 秒是在等一个死掉的 DNS 服务器超时。
修复 1:先把"慢"定位到 DNS 这一段
# === ★ "访问慢",要先拆开看慢在哪一段 ===
# === 一次网络请求,其实分好几段 ===
# 你以为的"访问一个接口",其实是一串步骤:
# 1. ★ DNS 解析:域名 -> IP(本文主角)
# 2. TCP 连接:和那个 IP 建立连接(三次握手)
# 3. TLS 握手:HTTPS 还要协商加密
# 4. 发请求 + 等服务器处理 + 收响应
# ★ "慢"可能卡在任何一段。不拆开,你根本不知道
# 是哪段的锅。
# === ★ curl -w:把每一段的耗时打出来 ===
$ curl -o /dev/null -s -w '
DNS解析: %{time_namelookup}s
TCP连接完成: %{time_connect}s
TLS握手完成: %{time_appconnect}s
开始传输: %{time_starttransfer}s
总耗时: %{time_total}s
' https://api.example.com/v1/ping
# ★ 这些时间是【累计】的(从请求发起算起):
# - time_namelookup = DNS 这一段花了多久
# - time_connect - namelookup = TCP 连接花了多久
# - time_total - starttransfer= 下载内容花了多久
# ★ 哪一段的增量大,就是哪一段慢。
# === ★ 我这次的判断 ===
# 慢的那次,time_namelookup 是 5.004,而 time_total
# 是 5.043 —— 5 秒全在 DNS 这一段,后面的连接、
# 传输加起来才 39 毫秒,和正常时一模一样。
# ★ 结论非常明确:接口没问题,网络没问题,
# 慢的就是【域名解析】这一步。
# === ★ 单独量域名解析有多慢 ===
# 想干净地只测解析,不掺杂后面的请求:
$ time getent hosts api.example.com
# 或:
$ time dig api.example.com
# ★ getent hosts 走的是【和你的程序完全一样】的
# 系统解析链路(见修复 2),最能复现程序遇到的
# 解析慢。dig 则是直接发 DNS 查询,稍有不同。
# === 认知 ===
# ★ "慢"是个结果,不是原因。第一步永远是把这一次
# 慢,拆成 DNS / 连接 / 传输几段,看清楚秒数到底
# 堆在哪一段。定错段,后面全是白费功夫。
修复 2:Linux 是怎么把域名翻译成 IP 的
# === ★ 搞清楚:一个域名,系统是怎么一步步解析的 ===
# === ★ 第一关:/etc/nsswitch.conf 决定"问谁" ===
# 程序要解析域名,系统先看 /etc/nsswitch.conf 的
# hosts 那一行,它规定了"按什么顺序、去哪些地方查":
$ grep hosts /etc/nsswitch.conf
hosts: files dns
# ^^^^^ ^^^
# ★ files:先查本地文件 /etc/hosts
# ★ dns :本地文件没有,再走 DNS 去网络上查
# 顺序是【从左到右】。所以解析一个域名,永远是
# "先翻 /etc/hosts,没有才去问 DNS"。
# === ★ 第二关:/etc/hosts —— 本地的"通讯录" ===
$ cat /etc/hosts
127.0.0.1 localhost
10.0.1.50 db-master # ★ 这里写死的,直接用
# ★ 如果一个域名在 /etc/hosts 里有,系统【立刻】
# 拿到 IP,根本不走 DNS、不会有任何网络等待。
# ★ 这也是一个排查/急救手段:把域名和正确 IP
# 写进 /etc/hosts,就能临时绕开有问题的 DNS。
# === ★ 第三关:/etc/resolv.conf —— DNS 怎么问 ===
# /etc/hosts 里没有,才走 DNS。问哪些 DNS 服务器、
# 怎么问,全看 /etc/resolv.conf:
$ cat /etc/resolv.conf
nameserver 10.0.0.99
nameserver 114.114.114.114
search internal.corp
options timeout:2 attempts:2
# ★ 几个关键项(下一节细讲):
# - nameserver:DNS 服务器地址,可多个,【从上往下】问。
# - search :搜索域,拼在短名字后面试。
# - options :超时、重试次数等行为参数。
# === ★ 完整链路串起来 ===
# 程序解析 api.example.com:
# ① 查 /etc/nsswitch.conf -> 得知"先 files 后 dns"
# ② 翻 /etc/hosts -> 没有这个域名
# ③ 读 /etc/resolv.conf -> 问 nameserver,从第一个起
# ④ 第一个 nameserver 10.0.0.99 死了 -> ★ 卡这里超时
# ⑤ 超时后问第二个 -> 拿到 IP
# ★ 我的 5 秒,就卡在第 ④ 步。
# === ★ 一个重要区别:dig 和程序解析走的不是一条路 ===
# dig / nslookup 是【直接】发 DNS 查询的工具,它
# ★ 不看 /etc/hosts、不看 nsswitch.conf。
# 而你的程序(以及 curl、ping、getent)走的是
# 【系统解析器】,要过 nsswitch、hosts 这些关。
# ★ 所以会出现"dig 能解析、程序却不行"——别奇怪,
# 它俩走的是两条路。复现程序的问题,用 getent。
# === 认知 ===
# ★ 域名解析不是一个黑盒。它是 nsswitch.conf ->
# /etc/hosts -> /etc/resolv.conf 这条清清楚楚的
# 链路。慢在哪、断在哪,顺着这条链一节节查。
修复 3:resolv.conf 的每一项,都在影响解析快慢
# === ★ 把 /etc/resolv.conf 的每一项讲透 ===
# === ★ nameserver:DNS 服务器,顺序极其关键 ===
nameserver 10.0.0.99
nameserver 114.114.114.114
# ★ 系统【严格从上往下】问。只有当上一个【超时/
# 失败】,才会去问下一个。
# ★ 所以:第一个 nameserver 要是又快又稳的那个。
# 把一个不稳定/已失效的 DNS 放第一位 —— 就是
# 我这次的坑,每次缓存失效都先去撞它、白等超时。
# ★ 注意:最多通常只认前 3 个 nameserver,写再多
# 也无用。
# === ★ options timeout:等一个 nameserver 多久 ===
options timeout:2
# ★ 单个 nameserver 的查询超时(秒)。【默认值是 5】。
# 我没写 options,用的就是默认 5 秒 —— 这正是
# 那个精确的"5 秒"的来源。
# ★ 调小(如 timeout:1 或 2),能让"撞到死 DNS"
# 时更快地放弃、转向下一个。是个有用的兜底。
# === ★ options attempts:整轮重试几次 ===
options attempts:2
# ★ 把整个 nameserver 列表轮询几遍。默认 2。
# ★ 最坏情况的等待 ≈ timeout × nameserver数 × attempts。
# 默认 5 × 2 × 2 = 20 秒 —— 解析能卡你 20 秒!
# (我这次第二个 DNS 是好的,第一轮就成了,所以
# 只卡 5 秒;若两个都慢,能卡到 20 秒。)
# === ★ options rotate:轮流用,别老压第一个 ===
options rotate
# ★ 加上 rotate,系统会在多个 nameserver 间轮流,
# 而不是每次都从第一个开始。能分摊压力。
# === ★ search:搜索域,一个隐蔽的"慢"来源 ===
search internal.corp example.com
# ★ search 的作用:当你解析一个【不带点的短名字】
# (如 myhost),系统会自动拼上 search 域去试:
# myhost.internal.corp、myhost.example.com ...
# ★ 坑:如果 search 域配得多,解析一个名字可能要
# 发好几轮查询,每轮都可能慢 —— 无谓地放大延迟。
# ★ 解析【完整域名】(带点的,如 api.example.com)
# 时,可加 options ndots 控制,或干脆精简 search。
# === ★ 看 resolv.conf 是不是被自动覆盖了 ===
# 很多环境里 /etc/resolv.conf 是被 NetworkManager、
# dhclient、云环境的 cloud-init 自动生成的 ——
# 你手改了,重启/续租 DHCP 后又被【覆盖回去】。
$ ls -l /etc/resolv.conf # 看是不是软链/谁管的
$ head -1 /etc/resolv.conf # 自动生成的文件开头常有注释
# ★ 真要固定,得改对应的源头配置(见修复 5)。
# === 认知 ===
# ★ resolv.conf 看着就几行,但 nameserver 的【顺序】、
# timeout/attempts 的【默认值】,直接决定了解析
# "撞到坏 DNS"时会卡你多少秒。
修复 4:DNS 排查的常用命令与典型故障
# === ★ 几个工具,以及它们各自适合查什么 ===
# === dig:最强的 DNS 排查工具 ===
$ dig api.example.com
# 重点看输出里:
# - ANSWER SECTION:解析出的 IP
# - Query time:这次查询耗时 —— ★ 慢不慢看它
# - SERVER:实际是哪个 DNS 应答的
# ★ 指定某个 DNS 来问(用来逐个测 nameserver):
$ dig @10.0.0.99 api.example.com +time=2 +tries=1
# +time 超时秒数,+tries 重试次数 —— 测某个 DNS
# 死没死,这俩参数让它快速失败、别傻等。
# === nslookup / host:更简洁的查询 ===
$ nslookup api.example.com
$ host api.example.com
# === ★ getent hosts:走系统解析链路(最贴近程序)===
$ getent hosts api.example.com
203.0.113.20 api.example.com
# ★ getent 会过 nsswitch、/etc/hosts,和你的程序
# 走同一条路。★ 复现"程序解析慢/失败",用它最准。
$ time getent hosts api.example.com # 量它到底多慢
# === ★ 典型故障 1:第一个 nameserver 死了(本文)===
# 现象:解析偶尔慢固定的 5 秒(或 timeout 设的值)。
# 定位:逐个 dig @每个nameserver +time=2 +tries=1,
# 找出那个 timed out 的。
# 处置:见修复 5。
# === ★ 典型故障 2:解析结果是错的 / 过期的 ===
# 现象:域名解析到一个旧 IP。多半是 DNS 缓存还存着
# 过期记录,或某一级 DNS 数据没更新。
$ dig api.example.com +noall +answer # 看 TTL 和 IP
# ★ 看 TTL:TTL 没到期前,缓存就是会给你旧值,
# 这是 DNS 的正常机制,不是 bug。
# === ★ 典型故障 3:完全解析不了 ===
$ dig api.example.com
;; ANSWER SECTION: (空的)
# 逐项查:resolv.conf 有没有配 nameserver?nameserver
# 通不通?域名本身在权威 DNS 上存不存在?
# === ★ 典型故障 4:search 域导致一堆无谓查询 ===
$ dig +search myhost # 看它拼了哪些后缀去查
# ★ 抓包能看得最清楚 —— 一次解析发了好几个 DNS 包:
$ tcpdump -i any -nn port 53
# 如果看到为一个名字反复查不同后缀,就是 search 的事。
# === 认知 ===
# ★ dig 用来测"DNS 服务器本身";getent 用来复现
# "程序实际遇到的解析"。两个配合,DNS 问题基本
# 无所遁形。
修复 5:正确解法——让域名解析又快又稳
# === ★ 解法:修好 nameserver,再加一层缓存兜底 ===
# === ★ 解法 1:把死掉的 nameserver 处理掉 ===
# 逐个测,找出坏的:
$ for ns in $(awk '/^nameserver/{print $2}' /etc/resolv.conf); do
echo -n "$ns : "
dig @$ns api.example.com +time=2 +tries=1 +short || echo FAIL
done
# ★ 把坏的删掉,或把好的、快的那个【放到第一位】:
nameserver 114.114.114.114 # ★ 又快又稳的放第一
nameserver 223.5.5.5 # 备用
# ★ 第一个 nameserver 的健康,直接决定大多数解析的
# 速度 —— 它必须是最可靠的那个。
# === ★ 解法 2:options 兜底,缩短"撞坏 DNS"的代价 ===
options timeout:2 attempts:2 rotate
# ★ 就算哪天某个 nameserver 又挂了,timeout:2 让
# 系统最多白等 2 秒就转走,而不是默认的 5 秒。
# 这是一道便宜又有效的"保险"。
# === ★ 解法 3:防止 resolv.conf 被自动覆盖 ===
# 手改 resolv.conf 常常重启就没。要改【源头】:
# - NetworkManager 环境:改网卡配置文件里的 DNS=
# /etc/sysconfig/network-scripts/ifcfg-eth0
# 然后 nmcli con reload。
# - 云服务器:DNS 常由 DHCP 下发,要在云控制台或
# dhclient 配置里改。
# ★ 别跟自动生成机制对着干,去改它的输入。
# === ★ 解法 4:上一层本地 DNS 缓存(根治"偶尔慢")===
# 我这次"偶尔慢"的本质:每次缓存失效,就要重新
# 走一遍解析、又撞上坏 DNS。★ 给机器装一个本地
# DNS 缓存服务,能极大减少真正出网的查询:
# 方案 A:nscd(name service cache daemon)
$ yum install -y nscd && systemctl enable --now nscd
# 方案 B:systemd-resolved,作为本地缓存解析器
$ systemctl enable --now systemd-resolved
$ systemd-resolve --status # 看状态和上游 DNS
# 方案 C:dnsmasq,轻量本地 DNS 缓存,很常用
$ yum install -y dnsmasq
# ★ 装了缓存后,resolv.conf 的 nameserver 指向
# 127.0.0.1(本地缓存),由它去管上游、做缓存。
# 绝大多数解析直接命中本地缓存,毫秒级返回。
# === ★ 解法 5:容器里的 DNS ===
# 容器的 /etc/resolv.conf 默认由 Docker 注入。
# - Docker 默认会把宿主机的 DNS 配进去(或用
# Docker 内置 DNS 127.0.0.11)。
# - 容器解析慢,先看容器内 cat /etc/resolv.conf。
# - 可在 daemon.json 里配 "dns": ["114.114.114.114"]
# 给所有容器统一指定。
# === ★ 解法 6:关键依赖,考虑绕开 DNS 不确定性 ===
# 对【极少变化、又极其关键】的内部域名,可以直接
# 写进 /etc/hosts —— 彻底不走 DNS,零解析延迟、
# 零 DNS 故障风险。★ 但代价是 IP 变了要手动改,
# 只适合非常稳定的目标,别滥用。
# === 验证 ===
$ for i in $(seq 20); do
curl -o /dev/null -s -w '%{time_namelookup}\n' \
https://api.example.com/v1/ping
done | sort -rn | head -3
# ★ 跑 20 次,看最慢的几次 —— 不应再出现 5 秒。
# DNS 解析耗时全程稳定在毫秒级,才算根治。
修复 6:DNS 排查纪律
# === 这次事故暴露的认知盲区,定几条纪律 ===
# === 1. ★ "访问慢"先拆段:DNS / 连接 / 传输,看秒数堆在哪 ===
$ curl -o /dev/null -s -w 'dns:%{time_namelookup} total:%{time_total}\n' URL
# === 2. ★ 域名解析是访问之前的独立一步,慢可能全卡在这 ===
# === 3. 解析链路:nsswitch.conf -> /etc/hosts -> /etc/resolv.conf ===
# === 4. ★ resolv.conf 的 nameserver 严格从上往下问,坏的在第一位会拖慢一切 ===
# === 5. ★ 单个 nameserver 默认超时 5 秒,"固定慢 5 秒"几乎就是它 ===
$ dig @ 域名 +time=2 +tries=1 # 逐个测 nameserver 死活
# === 6. options timeout/attempts 决定最坏等待,设小 timeout 兜底 ===
# === 7. ★ 复现程序的解析问题用 getent hosts,它走系统解析链路;dig 不走 hosts ===
# === 8. resolv.conf 常被 NetworkManager/DHCP 自动覆盖,要改源头配置 ===
# === 9. ★ "偶尔慢"多半是缓存失效后重新解析撞到坏 DNS,装本地 DNS 缓存根治 ===
# === 10. 排查"域名访问慢/不通"的步骤链 ===
$ curl -w time_namelookup # ① 确认慢在 DNS 这段
$ cat /etc/resolv.conf # ② 看配了哪些 nameserver
$ dig @每个nameserver +time=2 +tries=1 # ③ 逐个测,揪出坏的
$ getent hosts 域名 # ④ 用系统链路复现
$ 修 nameserver 顺序 + 装本地缓存 # ⑤ 根治
# 按这个顺序,"域名访问慢"基本能定位、能根治。
命令速查
需求 命令
=============================================================
把请求耗时拆段 curl -o /dev/null -s -w '%{time_namelookup} %{time_total}\n' URL
只测域名解析耗时 time getent hosts 域名
查域名解析(DNS 工具) dig 域名 / nslookup 域名 / host 域名
指定某个 DNS 来查 dig @ 域名 +time=2 +tries=1
走系统解析链路查(贴近程序) getent hosts 域名
看配了哪些 DNS 服务器 cat /etc/resolv.conf
看解析查询顺序 grep hosts /etc/nsswitch.conf
看本地 hosts 通讯录 cat /etc/hosts
看 systemd-resolved 状态 systemd-resolve --status
抓 DNS 查询包 tcpdump -i any -nn port 53
装本地 DNS 缓存 yum install -y nscd (或 dnsmasq)
口诀:访问慢先 curl -w 拆段,慢在 DNS 那一段就是域名解析的事,不是接口不是网络
resolv.conf 的 nameserver 从上往下问,坏的在第一位每次撞它等满 5 秒超时
避坑清单
- 访问一个接口慢先用 curl -w 把耗时拆成 DNS 解析连接传输几段,看清秒数到底堆在哪一段
- 域名解析是真正访问之前的一道独立工序,访问慢可能整段全卡在把域名翻译成 IP 这一步上
- Linux 解析链路是 nsswitch.conf 决定问谁,先翻 /etc/hosts 没有才走 /etc/resolv.conf 问 DNS
- resolv.conf 的 nameserver 严格从上往下问,只有上一个超时失败才问下一个,坏的在首位拖慢一切
- 单个 nameserver 的查询超时默认是 5 秒,固定慢 5 秒几乎就是在等一个死掉的 nameserver 超时
- options 的 timeout 和 attempts 决定最坏等待时间,默认配置最坏能卡你二十秒,timeout 应调小
- 复现程序的解析问题用 getent hosts 它走系统解析链路,dig 不看 hosts 和 nsswitch 走的是另一条路
- resolv.conf 常被 NetworkManager 或 DHCP 自动覆盖,手改重启就没,要去改对应的源头配置
- 偶尔慢多半是 DNS 缓存失效后重新解析又撞上坏 DNS,装 nscd 或 dnsmasq 本地缓存能根治
- 把又快又稳的 DNS 放 nameserver 第一位,关键稳定的内部域名可写进 hosts 彻底绕开 DNS 不确定性
总结
这次"接口偶尔慢、每次稳定慢 5 秒"的事故,纠正了我一个关于"访问"的、隐藏得很深的简化。在我的脑子里,"访问一个接口"长久以来就是一个单一的、不可再分的动作:我的程序,朝那个接口的地址,把请求"发"过去,然后等它"回"过来。在这个画面里,只有两个角色——我,和那个接口;中间是一条直接的、笔直的线。所以当有人告诉我"访问这个接口偶尔会慢 5 秒"时,我的怀疑对象,从一开始就被这个简化的画面框死了:慢,要么是线那头的接口慢(它处理得慢),要么是中间那条线慢(网络抖动)。我去压测接口,去查网络,翻来覆去,都是在这两个我能想到的角色身上找原因。我完全没有意识到,在我那个"程序直接访问接口"的画面里,被我无声无息地省略掉了一整个、而且是排在最前面的步骤。复盘到根上,我才明白,我的程序其实从来不知道那个接口"在哪"。它手里攥着的,只是一个域名——一串给人看的、好记的名字,api.example.com。可网络世界里,数据包要送达,认的不是名字,是 IP 地址。所以在真正的访问能够开始之前,必须先有一道翻译工序:把这个域名,翻译成一个 IP。这道工序,就是域名解析。它不是访问的一部分,它是访问的【前提】;它发生在我那条"笔直的线"还没画下第一笔之前。而我那 5 秒,一秒都没花在接口上,一秒都没花在网络传输上——它全部花在了这道我从未把它当回事、甚至从未意识到它存在的翻译工序里。更具体地说,我的系统在做翻译时,要按 /etc/resolv.conf 里写好的顺序,挨个去问几台 DNS 服务器"这个域名对应哪个 IP"。排在第一位的那台 DNS,早就已经悄悄地死掉了。可我的系统并不知道它死了,它老老实实地朝那台死掉的服务器发出询问,然后开始等——等一个永远不会来的回答。它要把默认的 5 秒超时整整等满,确认这台是真的不应答了,才肯转头去问第二台。第二台是好的,瞬间就回了。所以最终结果永远是对的,我也因此从没把它和"故障"联系起来——可那白白等掉的 5 秒,就是这么来的。这次最大的收获,是我意识到,我对一件事的排查能力,被我对这件事的"心理模型"死死地限制住了。我的模型里只有"程序"和"接口"两个角色,那么不管这个问题多么明显地指向第三个角色(域名解析),我也永远不可能怀疑到它头上——因为在我的世界观里,这第三个角色根本就【不存在】。我不是没查出它,我是压根没有把它纳入过"可以被怀疑的范围"。一个被你从模型里省略掉的环节,就是一个你天然的盲区:它出了任何问题,你都会归罪到别处去。所以下一次,当一个问题在我反复检查过的所有环节里都找不到原因时,我不会再一遍遍地加大力气去重查那几个老地方了。我会退后一步,做一件更根本的事:把我脑子里那个"事情是怎么发生的"的模型,亲手画出来,然后一个环节一个环节地追问——这一步和那一步之间,真的是直接相连的吗?还是说,中间其实还垫着一道我因为太习惯、而早已对它视而不见的工序?——很多时候,问题不在我反复检查的那几个环节里,而恰恰藏在那个被我简化掉、以为根本不存在的环节缝隙之中。
—— 别看了 · 2026