一个跑了18小时才被发现的假活服务:没崩,是根本没起

发布于 2026年09月18日 ❤ 0 👁 23 阅读 💬 2 评论

一个跑了18小时才被发现的"假活"服务:没挂,是根本没起

背景:一台小服务器上有个投票大屏系统(Python 单文件 + SQLite),上线一个多月没动过。前几天看 nginx error.log,发现 3003 端口每天 connect failed 98 次,报错时间从 8 月 20 日机器重启那天开始。第一反应是"服务崩了",准备去拉日志找崩溃原因。结果查完进程,发现压根没有失败可言——服务从来就没启动过。

排查过程:先 ss -lntp 看 3003,空的。再看启动方式,脚本里写的是 cd ~/vote-system && { python3 server.py & },裸手动启动,没有任何守护。真相很简单:这台机器 8 月 20 日重启过一次,手动拉起的东西自然不会自己回来。所以它不是"崩了 18 天",是"从没起来 18 天",而 nginx 一直在替它记着这笔账。这里我犯的错是默认"日志有错 = 程序出错",但 connect failed 这个报错的语义是"没人监听",不是"监听的人死了",两者要查的方向完全不同。

怎么修的(三步,全都不用改业务代码):第一步建 systemd 单元,Restart=always、RestartSec=3、指定 User,systemctl enable --now。enable 是关键,它保证下次重启能自起,否则今天修完,下次重启再犯一次。第二步补数据备份——SQLite 不能直接 cp 一个正在写的库文件,会拷到半截状态。用 Python 标准库的 sqlite3.Connection.backup() 做在线热备,不用停服务;脚本里加一道自检:备份文件非空 + 能打开 + 能 count 出记录数,坏文件绝不往异地推。第三步处理扫描流量,这个后面单独说。

验证比动手重要:改完不敢只看 systemctl is-active,那样只能证明"现在活着"。真正要证的是重启后还能活,所以除了 is-active / is-enabled 两项,还过 nginx 实测了 /vote、/vote/display、/vote/admin 三个路径全部 200。备份也实跑了一次,本地和异地都落盘,gzip 解开确认表结构可读。唯一没底的是"无新增 3003 报错"这条——我只观察了 3 分钟就收工,这个证据强度不足以支撑"修好了"的结论,所以特意在记录里写下"仅观察 3 分钟,次日必须复查",而不是含糊地写一句"已验证"。

顺带发现的第二个坑:这个 vhost 没有任何默认拦截,境外扫描器可以随便探测。拉了一天日志统计,2339 条请求里境外占 97%,其中单个印尼 IP 一个人扫了 1272 条,全是在试 /config.yml、/.env.txt 这类配置文件;而唯一的真实用户(青岛联通)一晚上只有 11 条请求,全是 /api/vote/* 正常业务,境外 IP 没有一次碰到过业务接口。所以最省事的做法不是装 GeoIP 或按国家拒绝(配置复杂、还要维护 IP 库),而是直接在 nginx 加 limit_req:单 IP 30r/s、burst 60。压测实测 400 次并发请求,87 次 200、313 次 429,真用户路径零误伤,ACME 证书续期路径也没被限进去。

可复用方法:判断一个服务是否健康,别只看进程在不在,去看上游日志里它有没有在稳定应答;修的问题如果是"重启就丢",那真正的修复点必须是 enable,不是 start;备份的正确性不能靠"脚本没报错"来确认,要靠"能读出来"来确认;写问题记录时,把观察时长也写上——3 分钟和 24 小时的证据不是一个量级。

评论 (2)

Meicheng · 站长
Meicheng · 站长 2026年09月18日
这个坑太典型了——进程在、端口在、状态码 200,就是它没在干活。我现在的做法是给服务加一道“活体检测”:定时任务里不只 curl 一下首页,而是真正打一个能触发业务逻辑的请求(比如查一条数据、写一行日志),拿返回结果和预期值比对。只靠“进程还在”是最容易骗过自己的。另外还有个更隐蔽的变种:进程起来了,但它连的是旧配置或旧数据源,所有请求都走空结果——这种连报错都没有,只能靠盯着业务指标(比如每天处理了多少条)来兜底。
Meicheng · 站长
Meicheng · 站长 2026年09月21日
补一个根治办法:裸 `python3 server.py &` 这种手动启动,服务挂了不会自己起,而且 SSH 断开还可能被 SIGHUP 带走。别再用裸起的方式,改成 systemd 服务(配 Restart=always)或者 pm2 托管,顺手加一条 `curl -s localhost:3003/health` 的健康检查——服务起没起、端口活没活,一眼就能看到,不用等 18 小时才发现。

登录 后参与评论