
调用外部命令时,测试环境里几行输出一切正常,到了 CI 却偶尔永远不退出。进程仍在、CPU 几乎为零,强制终止后也没有明确错误。问题往往不在命令本身,而在父进程只等退出、没有及时读取管道:日志把缓冲区写满后,双方就互相等待。

调用外部命令时,测试环境里几行输出一切正常,到了 CI 却偶尔永远不退出。进程仍在、CPU 几乎为零,强制终止后也没有明确错误。问题往往不在命令本身,而在父进程只等退出、没有及时读取管道:日志把缓冲区写满后,双方就互相等待。

大文件下载到 90% 时网络中断,最浪费的做法是从头再来。HTTP 字节范围请求允许客户端只取缺失部分,但可靠的断点下载绝不是把新响应直接追加到旧文件:服务器可能忽略范围,资源也可能已经更新。只有同时验证状态码、范围边界和资源版本,拼接后的文件才可信。

订单明细相加差一分钱、退款金额与原支付对不上、同一张账单在两个服务里得到不同结果,通常不是算术能力出了问题,而是系统没有约定金额的表示方式、舍入时机和余数归属。金额计算要追求的不是“看起来差不多”,而是每一步都可复现、可解释。

线上看到进程状态为 Z,第一反应往往是执行 kill -9。命令没有报错,僵尸却还在——这不是权限问题,而是目标已经结束运行,只剩父进程尚未领取的“退出回执”。理解 fork、退出与 waitpid 的配合,才能找到真正该修的进程。

接口已经检查了金额不能为负,为什么数据库里仍会出现脏数据?因为数据入口不只有当前服务:旧版本程序、后台脚本、批量导入和并发请求都可能绕过应用校验。真正不可破坏的业务不变量,应由最接近数据的数据库再守一道底线。

线上日志持续增长时,直接删除大文件未必能释放磁盘,简单改名也未必能让进程写入新文件。原因在于 Linux 进程持有的是指向文件对象的描述符,而不是一条会自动跟随变化的路径。把 logrotate 配置写对,关键不是记住几个参数,而是明确谁负责切换文件、进程何时重开描述符,以及怎样证明空间真的被回收。

C/C++ 的越界写入、释放后使用往往不会在错误发生处立刻崩溃:被破坏的数据可能经过许多调用后才引发异常,Core Dump 留下的栈也只是最后一站。AddressSanitizer(ASan)通过编译期插桩,把这类错误尽量变成发生位置明确、可以重复验证的测试失败。

同一台机器上的反向代理、守护进程与业务服务,经常不需要暴露 TCP 端口。Unix Domain Socket(UDS)用文件系统路径标识端点,既能复用成熟的 Socket 编程模型,又能借助目录权限缩小访问范围。但“把端口换成路径”只是开始,消息边界、残留文件和背压仍需明确设计。

“备份任务每天成功”只证明某个作业没有报错,不能证明数据真的可恢复。权限失效、密钥丢失、文件截断、版本不兼容,都可能让一排绿色记录在事故当天失去意义。可靠的备份体系应从恢复目标倒推,并用周期性演练验证整条链路。

服务从“每连接一个线程”改成 epoll 后,压测时却偶尔有连接停住,重启才恢复。问题通常不在 epoll_wait() 本身,而在程序混淆了“已经有数据”和“内核通知数据变化”这两件事。理解 LT、ET 的通知语义,并把 Socket、读取循环和业务状态机配套设计,才能避免看似随机的漏事件。