Linux 系统服务管理与优化方法

1次阅读

直接用 journalctl 查日志最快,90% 问题日志有明确线索;注意 execstart 路径必须绝对且可执行、环境变量需显式声明、启动超时需按场景处理、reload 需配 execreload 或信号。

Linux 系统服务管理与优化方法

systemctl 启动失败时怎么看日志

服务启动失败,systemctl start 返回 “failed” 但没说清原因,直接看 journalctl 最快。别先翻配置文件,90% 的问题日志里有明确线索。

常用组合:

  • journalctl -u <code>nginx –since “2 minutes ago”:只查刚启动的 nginx 日志,避免被历史刷屏
  • journalctl -u <code>mysql -n 50 -f:实时跟踪最后 50 行,适合调试启动卡住场景
  • journalctl -u <code>redis | grep -i “permission|denied|address already in use”:快速过滤权限或端口冲突类错误

注意:journalctl 默认不持久化,重启后旧日志可能丢失。若需长期保留,改 /etc/systemd/journald.conf 中的 Storage=persistent 并执行 systemctl restart systemd-journald

service 文件里 ExecStart 写错路径会静默失败

systemdExecStart 路径校验极严:路径不存在、权限不足、不是可执行文件,都会导致服务状态为 inactive (dead),但 systemctl status 可能只显示 “Started …” 而不报错。

排查要点:

  • ls -l /usr/local/bin/myapp 确认路径存在且有 x 权限
  • 不要写 ExecStart=python3 /opt/app/main.py —— systemd 不走 shell,找不到 python3;应写绝对路径:ExecStart=/usr/bin/python3 /opt/app/main.py
  • 如果程序依赖环境变量(如 PYTHONPATH),必须显式在 service 文件中用 Environment= 设置,不能靠用户 shell 的 .bashrc

一个典型坑:which python3 输出是 /usr/bin/python3,但某些系统装了 pyenv 或 conda,实际要用 /home/deploy/.pyenv/shims/python3 —— 这个路径通常不可执行,得换用真实解释器路径。

服务启动慢,systemd 等不及就 kill 掉

默认情况下,systemd 启动服务后只等 90 秒(DefaultTimeoutStartSec),超时就发 SIGTERM 强杀。常见于数据库初始化、Java 应用预热、或首次生成证书的场景。

解决方法不是无脑调大 timeout,而是分情况处理:

  • 确认是否真需要那么久:用 strace -f -e trace=execve,openat,connect <code>/usr/bin/myapp 看卡在哪一步
  • 如果是冷启动耗时,加 TimeoutStartSec=300 到 service 文件的 [Service]
  • 如果只是“业务就绪”慢(比如 http 端口监听了但健康检查未通过),用 Type=notify + systemd-notify --ready 在代码里主动通知就绪,比硬等更可靠

注意:TimeoutStartSec 是 per-service 配置,改全局要动 /etc/systemd/system.conf,一般没必要。

systemctl reload 不生效?可能是 ReloadSignal 或 ExecReload 没配对

很多服务支持热重载(如 Nginx、Redis),但 systemctl reload 要求 service 文件明确告诉 systemd 怎么做。没配 ExecReload 或信号不对,命令就静默成功但实际没 reload。

验证和修复步骤:

  • 查服务是否支持 reload:systemctl show <code>nginx | grep -E “(ExecReload|ReloadSignal)”
  • 标准写法:ExecReload=/usr/sbin/nginx -s reload(Nginx)或 ExecReload=/bin/kill -s HUP $MAINPID(多数 daemon)
  • 如果服务用 Type=notify,reload 时也要确保进程收到信号后能正确响应,否则 reload 成功但配置未更新

一个隐蔽问题:某些打包版本(如 ubunturedis-server)service 文件里根本没写 ExecReloadsystemctl reload redis 实际执行的是 restart,会中断连接 —— 得自己补上。

真正难的不是写对一行 ExecStart,而是理解 systemd 把“启动”拆成了路径校验、权限检查、cgroup 分配、依赖排序、超时控制、就绪通知多个阶段,每个阶段失败的表现都不同。日志、路径、信号、类型这四个点串起来,80% 的服务管理问题就定位得差不多了。

text=ZqhQzanResources