systemd服务平滑重启需服务自身支持信号处理(如SIGUSR2)且unit文件正确配置ExecReload;直接restart会中断连接,reload才可能不中断。

systemd 服务如何实现平滑重启(SIGUSR2 / reload)
多数现代 Linux 服务(如 nginx、haproxy、redis)支持不中断连接的重载配置,但前提是服务本身实现了信号处理逻辑,并且 systemd 单元文件正确声明了重载方式。直接执行 systemctl restart 默认会 kill 进程再拉起,不是平滑的。
真正平滑的关键是用 systemctl reload 或 systemctl try-reload-or-restart,它们会向主进程发送 SIGUSR1 或 SIGUSR2(具体取决于服务实现),由服务自行决定是否 fork 新 worker、逐步关闭旧连接等。
-
nginx:支持reload,旧 worker 处理完已有请求后退出,新 worker 接管新连接 -
haproxy:需启用stats socket+reload,或使用systemctl reload haproxy(v2.0+ 内置 graceful reload) -
redis:不支持 reload 配置(无运行时重载能力),systemctl reload redis实际退化为 restart,必须避免 - 自定义服务:需在
.service文件中设置ExecReload=,例如ExecReload=/bin/kill -s USR2 $MAINPID
自定义服务 unit 文件中 ExecReload 的写法要点
如果服务支持 SIGUSR2 触发平滑重载,但默认 unit 文件没配 ExecReload,就需要手动补全。错误写法(比如只写 KillSignal=USR2)不会触发 reload 行为;正确做法是显式指定命令。
- 必须用
$MAINPID,不能硬编码 PID 文件路径——systemd 不保证 PID 文件存在或及时更新 - 推荐写法:
ExecReload=/bin/kill -s USR2 $MAINPID,加/bin/kill是为了兼容最小化系统(busybox 可能没kill命令) - 若服务要求先写配置再发信号,应写成两行:
ExecReload=/usr/bin/cp /tmp/new.conf /etc/myapp.conf+ExecReload=/bin/kill -s HUP $MAINPID(注意:systemd 会按顺序执行所有ExecReload行) - 务必搭配
Type=notify或Type=simple+GuessMainPID=yes,否则$MAINPID可能为空
验证 reload 是否真平滑:看连接和日志
别只信“命令没报错”,得观察实际行为。常见误判是看到 systemctl reload xxx 返回成功,就以为连接没断——其实可能服务内部只是 reload 了配置,但没做连接迁移。
专为中小型企业定制的网络办公软件,富有竞争力的十大特性: 1、独创 web服务器、数据库和应用程序全部自动傻瓜安装,建立企业信息中枢 只需3分钟。 2、客户机无需安装专用软件,使用浏览器即可实现全球办公。 3、集成Internet邮件管理组件,提供web方式的远程邮件服务。 4、集成语音会议组件,节省长途话费开支。 5、集成手机短信组件,重要信息可直接发送到员工手机。 6、集成网络硬
- 用
ss -tulnp | grep :port看监听 socket 是否始终存在(PID 不变或仅短暂中断) - 对 HTTP 服务,用
curl -v http://localhost/health持续请求,同时执行systemctl reload,观察是否出现Connection refused或超时 - 查服务日志:
journalctl -u xxx -n 50 --no-pager,确认有类似reloading configuration、gracefully shutting down worker的记录,而非exiting+starting - 某些服务(如旧版
nginx)在 reload 失败时静默回退到旧配置,需检查nginx -t是否通过,否则 reload 实际未生效
supervisord 或其他进程管理器下如何模拟平滑重启
如果你没用 systemd,而是用 supervisord、runit 或裸 nohup 启动服务,那“平滑”完全依赖服务自身是否提供 reload 接口——supervisord 本身不理解“平滑”,它的 supervisorctl reload 就是 stop + start。
-
supervisord:只能靠服务暴露的 HTTP API 或 socket 控制(如nginx -s reload),需在supervisord.conf中把 reload 命令写进command字段,再用supervisorctl signal USR2 myapp手动发信号 - 裸进程:用
kill -USR2 $(cat /var/run/myapp.pid),但必须确保 PID 文件可靠(建议改用pidof myapp或pgrep -f "myapp.*master") - 注意信号权限:非 root 用户启动的服务,不能被 root 用
kill发信号(除非用sudo -u user kill) - 没有 reload 支持的服务(如纯 Python Flask app),唯一办法是上反向代理(
nginx或traefik)做连接保持 + 蓝绿部署,这不是 reload,而是架构层规避
平滑重启不是 systemctl 的默认行为,它依赖服务实现、unit 配置、信号语义三者对齐。最容易忽略的是:reload 命令成功 ≠ 配置已生效 ≠ 连接未中断 —— 必须结合日志和连接状态交叉验证。









