网络问题和系统问题最怕一上来就猜。正确的姿势是分层:先确认 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 诊断

doggodig 的现代替代,彩色输出、表格式展示、原生支持 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 — 进程管理

htoptop 的增强版,彩色、支持鼠标、交互式:

快捷键功能
F6选排序方式(按 CPU / 内存 / 时间)
F5树形视图(看父子关系,找哪个 worker 占了资源)
/搜索进程名
u按用户过滤
F9发信号(SIGTERM / SIGKILL

典型流程:glances 发现 CPU 占用高 → htop 按 CPU 排序 → 定位异常进程 → 查日志确认原因。

bmon — 网络带宽

bmon 实时显示网卡流量,带历史曲线图。流量突增的时间点一目了然。

bmon              # 所有网卡
bmon -p eth0      # 指定网卡

看到某时刻带宽饱和后,回 htop 按网络用量排序定位是哪个进程在传输。

ncdu — 磁盘空间

ncdudu 的交互式版本,快速找出什么占用了磁盘:

ncdu /            # 扫描整个文件系统
ncdu /var/log     # 从可疑目录开始

界面内用方向键导航,按 s 按大小排序,定位到大文件后按 d 删除(有确认)。

注意:先确认文件职责再删。/var/log 里的日志通常可以清理;/var/lib 里的数据库文件绝对不能随便删。

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 / 移动网络后连接自动恢复。

SSHmosh
网络切换断开,需重连自动恢复
高延迟输入等待回显本地即时显示
服务器依赖仅需 sshd需安装 mosh-server
端口TCP 22UDP 60000-61000

适合场景:移动网络、不稳定 WiFi、跨国 SSH(高延迟)。服务器端需要安装 mosh-server 并开放对应 UDP 端口。认证仍然走 SSH 密钥,配置见 SSH

7. 协议层速查

层级工具排查什么
DNSdoggo域名能否解析、解析结果是否正确、本地和公共 DNS 是否一致
连接ping / nc -zv host port主机可达?端口开放?防火墙?
HTTPxh --verbose / curl -v请求头、响应头、状态码、重定向链路、TLS 证书
gRPCgrpcurl服务是否注册、方法调用是否正常、参数类型
系统资源glanceshtopbmonncduCPU / 内存 / 网络 / 磁盘的瓶颈定位
日志lnav多服务时间线、错误模式、频率突增

8. 原则

分层,不要猜:DNS 解析正常不代表端口可达,HTTP 200 也不代表业务正确。每层独立确认。

verbose 先于感觉xh --verbosecurl -vssh -vvv 会把握手过程、请求头、错误位置都打出来,比盲猜快得多。

诊断结果留记录:关键指标、时间点和处理动作写下来,方便复盘和交接给值班同事。

调试凭据要脱敏:复制请求命令或截图前,检查 Authorization、Cookie、Token 和内部域名。