系统网络调试与生产检查表 / System and Network Debugging and Production Checklist
1. 为什么需要调试路线
系统网络故障最怕一句“卡了”或“连不上”。真正的排查要先定位层级:进程是否还活着、线程是否在跑、fd 是否泄漏、端口是否监听、TCP 状态是什么、协议 parser 卡在哪个状态、CPU 和内存是否到瓶颈。
symptom
-> process state
-> fd/socket state
-> syscall blocking point
-> protocol state
-> resource limits
-> root cause evidence2. 第一现场清单
看到故障先保存现场,不要先重启:
- 时间、机器、版本、commit、配置;
- pid、命令行、环境变量摘要;
- CPU、内存、fd 数、线程数;
- 端口监听和连接状态;
- 最近错误日志和 core dump;
- 是否有发布、配置、依赖、流量变化。
3. 进程是否活着
ps -o pid,ppid,state,etime,cmd -p <pid>
pstree -p <pid>
cat /proc/<pid>/status
journalctl -u service-name --since "10 min ago"进程状态 R/S/D/Z 含义不同。D 状态常表示不可中断 I/O 等待,Z 是 zombie,不能用普通 kill 解决。
4. 卡在哪里
strace 是系统调用视角。程序卡住时先看它最后停在哪个系统调用:read、accept、connect、futex、epoll_wait、wait4、openat 都代表不同方向。
strace -p <pid>
strace -f -tt -T -p <pid>
gdb -p <pid> -ex 'thread apply all bt'5. fd 是否泄漏
ls -l /proc/<pid>/fd | wc -l
lsof -p <pid>
cat /proc/<pid>/limitsfd 泄漏可能表现为 accept/open/socket 失败,errno 是 EMFILE 或 ENFILE。要区分进程级上限和系统级上限。
6. 端口和 TCP 状态
ss -lntp
ss -antp 'sport = :8080 or dport = :8080'
tcpdump -i any port 8080 -nnSYN-SENT、SYN-RECV、ESTABLISHED、FIN-WAIT、CLOSE-WAIT、TIME-WAIT 都指向不同关闭或拥塞问题。CLOSE-WAIT 多常说明本进程没有关闭对端已关闭的连接。
7. 协议现场
协议日志要记录 parser state、已读字节、目标长度、限制、connection id 和关闭原因。抓包只能看到字节,业务 parser 才知道为什么拒绝。二者要能关联。
8. 性能现场
top -H -p <pid>
perf top -p <pid>
perf record -g -p <pid>
pidstat -t -p <pid> 1
vmstat 1
iostat -xz 1CPU 满、I/O 等待高、上下文切换高、锁等待高、page fault 高,是不同问题。不要只看平均 CPU。
9. 内存现场
pmap -x <pid>
cat /proc/<pid>/smaps_rollup
cat /proc/<pid>/maps
valgrind --tool=massif ./program网络服务的内存暴涨常来自 output buffer 无背压、请求体无限制、连接对象泄漏或日志堆积。
10. 复盘模板
symptom:
impact:
first bad time:
version/config change:
process evidence:
fd/socket evidence:
syscall evidence:
protocol evidence:
resource evidence:
root cause:
fix:
regression test:
dashboard/log/checklist update:11. 发布前检查
- 每个 fd/socket 都有 RAII 和关闭路径。
- 每个阻塞调用都有超时或关闭唤醒策略。
- 网络 parser 有大小限制和 fuzz 样本。
- 日志包含 pid、fd、connection id、peer、errno、状态。
- CI 跑基础系统测试和协议半包测试。
- 生产有 core dump、符号、版本和配置记录。
12. 总结
调试篇的目标是把“感觉哪里坏了”变成“证据显示坏在这一层”。系统网络程序的真相常在内核状态、系统调用、fd 表、TCP 状态和协议 parser 中,C++ 日志必须能和这些外部证据对齐。
深化切片 1:最小实验
围绕 process 和 strace 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 2:错误注入
围绕 strace 和 fd 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 3:外部观察
围绕 fd 和 socket 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 4:RAII 封装
围绕 socket 和 TCP state 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 5:并发边界
围绕 TCP state 和 parser 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 6:生产复盘
围绕 parser 和 perf 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 7:最小实验
围绕 perf 和 memory 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 8:错误注入
围绕 memory 和 process 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 9:外部观察
围绕 process 和 strace 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 10:RAII 封装
围绕 strace 和 fd 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 11:并发边界
围绕 fd 和 socket 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 12:生产复盘
围绕 socket 和 TCP state 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 13:最小实验
围绕 TCP state 和 parser 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 14:错误注入
围绕 parser 和 perf 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 15:外部观察
围绕 perf 和 memory 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 16:RAII 封装
围绕 memory 和 process 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 17:并发边界
围绕 process 和 strace 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 18:生产复盘
围绕 strace 和 fd 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 19:最小实验
围绕 fd 和 socket 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 20:错误注入
围绕 socket 和 TCP state 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 21:外部观察
围绕 TCP state 和 parser 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 22:RAII 封装
围绕 parser 和 perf 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 23:并发边界
围绕 perf 和 memory 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 24:生产复盘
围绕 memory 和 process 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 25:最小实验
围绕 process 和 strace 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 26:错误注入
围绕 strace 和 fd 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 27:外部观察
围绕 fd 和 socket 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 28:RAII 封装
围绕 socket 和 TCP state 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 29:并发边界
围绕 TCP state 和 parser 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 30:生产复盘
围绕 parser 和 perf 做一次工程练习。记录命令、errno、pid、fd、路径、peer、字节数和状态,保证另一个人能复现。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 31:最小实验
围绕 perf 和 memory 做一次工程练习。用一个最小程序观察一个系统行为,不要把 shell、库封装和业务代码混在一起。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 32:错误注入
围绕 memory 和 process 做一次工程练习。故意制造一个失败条件,例如文件不存在、权限不足、子进程退出码非零、管道对端关闭或映射越界。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 33:外部观察
围绕 process 和 strace 做一次工程练习。用 ps、strace、lsof、pmap、ss、tcpdump 或调试器观察内核状态,而不是只看 C++ 变量。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 34:RAII 封装
围绕 strace 和 fd 做一次工程练习。把资源获取、移动、释放和失效状态写进类型,避免正常路径能释放、异常路径泄漏。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。
深化切片 35:并发边界
围绕 fd 和 socket 做一次工程练习。系统调用可能阻塞,信号可能打断等待,多个线程可能同时操作同一个资源。
hypothesis
-> minimal program
-> external observation
-> failure injection
-> engineering rule复盘时要说明:这个现象属于 C++ 对象生命周期、POSIX/系统调用语义、内核调度、文件系统、虚拟内存,还是网络协议。分层越清楚,系统网络调试与生产检查表 就越不容易学成 API 背诵。