现场是这样的。Ubuntu 22.04 上用 systemd socket 激活一个 python 服务,第一次请求要等八秒才返回,之后都是几十毫秒,journalctl 里 socket 单元一直 active,service 单元显示刚启动。
中间走过弯路,把「ProtectHome 和 PrivateTmp 让首次读配置变慢」当成主因,改完现象没变。
把日志和配置对完,能解释这个现象的基本就这几处。socket 激活要等实例起来,冷启动时导入模块的时间全算在首请求里;服务启动时做数据库连接池预热,第一次要把连接建满;socket 的 Backlog 太小,并发首请求只能排队。
上来先看首请求卡在哪一段
journalctl -u app.socket -u 'app@*' --since '5 min ago' --no-pager | tail -30
量一次冷启动的服务耗时
systemd-analyze blame | head -10 && time systemctl start app.service
预启动服务并保留 socket
systemctl enable app.socket && systemctl start app.socket && systemctl start app.service
调大 backlog 减少排队
printf '%s
' '[Socket]' 'ListenStream=8080' 'Backlog=1024' > /etc/systemd/system/app.socket.d/backlog.conf
怎么算真的好了,看的是同一批现象。第一次 curl 的耗时从八秒降到 500ms 以内,journalctl 里 service 启动耗时稳定在 300ms 左右。
这里还有个坑。socket 激活省的是常驻内存,代价就是冷启动时间,延迟敏感的接口不适合这么部署;Accept=yes 每个连接都 fork,开销不小。这类问题最好一次改到位,反复小改反而容易把原因搅混。
