网络问题和系统问题最怕一上来就猜。正确的姿势是分层:先确认 DNS 能解析,再确认网络可达,再看 HTTP 请求的完整链路,最后看应用日志。每一层有对应的工具,每一层的问题有不同的特征。本文按这条排查主线组织,工具服务于方法。
1. 排查的分层模型
DNS 层 doggo example.com → 域名能否解析?解析到哪里?
连接层 ping / nc -zv host port → 网络可达?端口开放?
HTTP 层 xh --verbose https://... → 请求是否到达?响应头和状态码是什么?
应用层 lnav / 服务日志 → 业务逻辑是否报错?从下往上逐层确认,每一层确认正常后再往上走。“HTTP 返回 500”和”HTTP 连接超时”是完全不同层级的问题,不能用同一套排查路径。
2. HTTP 调试
xh — 日常 API 调试
xh 用 Rust 实现,继承了 HTTPie 的友好语法。日常调试 REST API,xh 比 curl 写起来快:
# GET(默认)
xh https://api.example.com/users
# POST JSON(= 字符串,:= 原始值)
xh POST https://api.example.com/users name=Alice age:=30
# 添加请求头
xh https://api.example.com Authorization:"Bearer token123"
# 查询参数
xh https://api.example.com/search q==hello page==1
# 查看完整请求和响应(调试首选)
xh --verbose https://httpbin.org/headers
# 结合 jq 处理响应
xh https://api.github.com/repos/torvalds/linux | jq '.stargazers_count'xh 的语法接近”说话”:key=value 是 JSON 字段,不用手写 -H "Content-Type: application/json" 和 -d '{...}'。
登录 + 后续请求的调试工作流:
TOKEN=$(xh POST api.example.com/login username=admin password=secret | jq -r '.token')
xh GET api.example.com/admin "Authorization:Bearer $TOKEN" | jq '.users[].name'curl — 不可替代的场景
xh 还不够成熟的地方,curl 更合适:
- 脚本和 CI:curl 跨平台、无额外依赖,行为稳定
- 复杂认证:client certificate、Kerberos、NTLM,xh 支持有限
- 精确控制:连接超时、重试策略、原始字节级调试(
--trace) - 文件上传/下载:curl 的大文件处理和断点续传更成熟
# 带超时和重试
curl --connect-timeout 5 --retry 3 https://api.example.com/health
# 查看完整请求和响应头
curl -v https://example.com
# 证书调试(跳过验证仅用于测试,不用于生产)
curl -k https://self-signed.example.com原则:交互调试和一次性探索用 xh,脚本和 CI 用 curl。
3. DNS 诊断
doggo 是 dig 的现代替代,彩色输出、表格式展示、原生支持 DoH/DoT 加密查询。
doggo example.com # 查 A 记录(IPv4)
doggo example.com AAAA # IPv6
doggo example.com MX # 邮件服务器
doggo example.com TXT # TXT 记录(域名验证、SPF)
doggo example.com CNAME # 别名
# 对比不同 DNS 服务器的解析结果
doggo example.com @1.1.1.1 # Cloudflare
doggo example.com @8.8.8.8 # Google
# JSON 输出(脚本处理)
doggo example.com --json | jq '.responses[].answers[].address'常见用法:定位 DNS 缓存问题
doggo example.com # 本地 DNS
doggo example.com @8.8.8.8 # Google DNS
# 两个结果不一致 → 本地 DNS 缓存过期或被污染
# 结果一致但 IP 不对 → 上游 DNS 问题或 CDN 配置问题新域名上线、DNS 迁移、SSL 证书申请失败时,先用这个对比确认传播状态。
4. gRPC 调试
gRPC 不是 HTTP,浏览器和 xh/curl 无法直接调试。grpcurl 是 gRPC 世界的 curl。
前提:服务端需要启用 server reflection,否则需要手动提供 .proto 文件。
# 列出服务端所有可用服务
grpcurl -plaintext localhost:50051 list
# 列出某个服务的所有方法
grpcurl -plaintext localhost:50051 list mypackage.MyService
# 查看方法参数结构
grpcurl -plaintext localhost:50051 describe mypackage.MyService/GetUser
# 调用方法
grpcurl -plaintext \
-d '{"id": 123}' \
localhost:50051 \
mypackage.MyService/GetUser
# 带认证 header
grpcurl -plaintext \
-H "Authorization: Bearer token" \
-d '{"name": "test"}' \
localhost:50051 \
mypackage.MyService/CreateUser
# 服务端没有 reflection 时,用 .proto 文件
grpcurl -proto service.proto \
-d '{"name": "test"}' \
localhost:50051 \
mypackage.MyService/CreateUser本地开发的 gRPC 服务通常没有 TLS,必须加 -plaintext,否则会报证书错误。
用 describe 查方法签名,是验证 API 契约和排查参数类型错误的最快方式——不需要写客户端代码。
5. 系统资源诊断链路
系统变慢或出问题时,按这条链路诊断:
glances(全景)→ htop(定位进程)→ bmon(看网络)→ ncdu(找磁盘)→ lnav(看日志)glances — 系统全景
SSH 到服务器后先跑 glances,10 秒内了解系统整体状态——CPU、内存、网络、磁盘 I/O、进程、温度一个界面全显示。颜色直接告诉你严重程度:绿色正常、黄色警告、红色危险。
glances # 交互模式
glances -w # Web 模式(浏览器访问 :61208,适合远程监控)看到 CPU 红色后进 htop 定位具体进程;看到网络黄色后进 bmon 看带宽。
htop — 进程管理
htop 是 top 的增强版,彩色、支持鼠标、交互式:
| 快捷键 | 功能 |
|---|---|
F6 | 选排序方式(按 CPU / 内存 / 时间) |
F5 | 树形视图(看父子关系,找哪个 worker 占了资源) |
/ | 搜索进程名 |
u | 按用户过滤 |
F9 | 发信号(SIGTERM / SIGKILL) |
典型流程:glances 发现 CPU 占用高 → htop 按 CPU 排序 → 定位异常进程 → 查日志确认原因。
bmon — 网络带宽
bmon 实时显示网卡流量,带历史曲线图。流量突增的时间点一目了然。
bmon # 所有网卡
bmon -p eth0 # 指定网卡看到某时刻带宽饱和后,回 htop 按网络用量排序定位是哪个进程在传输。
ncdu — 磁盘空间
ncdu 是 du 的交互式版本,快速找出什么占用了磁盘:
ncdu / # 扫描整个文件系统
ncdu /var/log # 从可疑目录开始界面内用方向键导航,按 s 按大小排序,定位到大文件后按 d 删除(有确认)。
注意:先确认文件职责再删。/var/log 里的日志通常可以清理;/var/lib 里的数据库文件绝对不能随便删。
lnav — 日志查看
lnav 让多个日志文件合并在一条时间线上显示,自动识别格式(nginx、syslog、JSON):
lnav /var/log/ # 浏览整个日志目录
lnav access.log app.log # 多文件合并时间线
lnav -t app.log # 实时追踪(像 tail -f)在界面里按 ; 可以用 SQL 查询日志:
SELECT count(*), log_level FROM logline GROUP BY log_level;
SELECT * FROM logline WHERE log_body LIKE '%error%' LIMIT 20;排查生产问题时,把 nginx 日志、应用日志、数据库日志同时扔给 lnav,错误之间的因果关系(nginx 在 14:03:21 报 502,应用在 14:03:20 开始 OOM)在时间线里一眼就能看到。
6. 远程连接
mosh 解决 SSH 在不稳定网络下的两个痛点:网络切换会断连,高延迟下输入体验差。
mosh user@host # 用法与 SSH 相同
mosh --ssh="ssh -p 2222" user@host # SSH 走非标准端口mosh 基于 UDP,本地回显(你打字立即显示,不等服务器确认),切换 WiFi / 移动网络后连接自动恢复。
| SSH | mosh | |
|---|---|---|
| 网络切换 | 断开,需重连 | 自动恢复 |
| 高延迟输入 | 等待回显 | 本地即时显示 |
| 服务器依赖 | 仅需 sshd | 需安装 mosh-server |
| 端口 | TCP 22 | UDP 60000-61000 |
适合场景:移动网络、不稳定 WiFi、跨国 SSH(高延迟)。服务器端需要安装 mosh-server 并开放对应 UDP 端口。认证仍然走 SSH 密钥,配置见 SSH。
7. 协议层速查
| 层级 | 工具 | 排查什么 |
|---|---|---|
| DNS | doggo | 域名能否解析、解析结果是否正确、本地和公共 DNS 是否一致 |
| 连接 | ping / nc -zv host port | 主机可达?端口开放?防火墙? |
| HTTP | xh --verbose / curl -v | 请求头、响应头、状态码、重定向链路、TLS 证书 |
| gRPC | grpcurl | 服务是否注册、方法调用是否正常、参数类型 |
| 系统资源 | glances → htop → bmon → ncdu | CPU / 内存 / 网络 / 磁盘的瓶颈定位 |
| 日志 | lnav | 多服务时间线、错误模式、频率突增 |
8. 原则
分层,不要猜:DNS 解析正常不代表端口可达,HTTP 200 也不代表业务正确。每层独立确认。
verbose 先于感觉:xh --verbose、curl -v、ssh -vvv 会把握手过程、请求头、错误位置都打出来,比盲猜快得多。
诊断结果留记录:关键指标、时间点和处理动作写下来,方便复盘和交接给值班同事。
调试凭据要脱敏:复制请求命令或截图前,检查 Authorization、Cookie、Token 和内部域名。