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

线上看到进程状态为 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、读取循环和业务状态机配套设计,才能避免看似随机的漏事件。

告警显示 Load Average 突然升到 20,服务器就一定是 CPU 不够吗?不一定。Linux 的系统负载既包含正在使用或等待 CPU 的任务,也包含处于不可中断睡眠的任务。后者常在等待磁盘、网络文件系统或内核 I/O。把负载直接当成 CPU 使用率,扩容很可能扩错方向。

限流、审计和地域判断经常依赖客户端 IP,但应用部署到 CDN、负载均衡器或网关之后,套接字看到的通常只是上一跳代理。直接取 X-Forwarded-For 的最左值看似解决了问题,却可能把攻击者自己填写的地址当成事实。真正可靠的做法不是“找一个请求头”,而是先划出可信代理边界。

一条看似简单的筛选语句漏掉了数据,NOT IN 在测试库正常、上线后却返回空集,统计结果还总比总行数小——这些问题常常不是数据库算错了,而是代码把 NULL 当成了普通值。理解三值逻辑,再把“未知”纳入表结构与测试,才能让查询结果符合业务直觉。