🔧 第10课:系统服务(systemd)

阶段二:用户与进程第4/6课

📚 课程目标

一、systemd概述

1.1 为什么是systemd

systemd是现代Linux的初始化系统(init system),替代了传统的SysV init。它不仅管理服务启动,还提供日志、定时器、挂载、网络等统一管理。

📋 SysV init vs systemd

特性SysV initsystemd
启动方式串行执行脚本并行启动服务
依赖管理手动LSB头声明式依赖
服务监控自动重启(cgroup)
日志分散在/var/logjournald统一
定时任务cronTimer单元
套接字激活支持

1.2 systemd核心组件

systemd ──┬── systemd-init     # PID 1,init进程
           ├── systemctl        # 服务管理命令
           ├── journalctl       # 日志查询
           ├── systemd-analyze  # 启动分析
           ├── logind           # 登录管理
           ├── resolved         # DNS解析
           ├── networkd         # 网络管理
           └── timesyncd        # 时间同步

二、Unit单元类型

类型后缀功能
Service.service服务守护进程
Target.target运行级别/状态组
Timer.timer定时任务
Socket.socket套接字激活
Mount.mount文件系统挂载
Path.path路径监控
Swap.swapSwap空间
Slice.sliceCgroup资源控制组

2.1 Unit文件位置(优先级从高到低)

/etc/systemd/system/          # 管理员自定义(最高优先级)
/run/systemd/system/          # 运行时动态生成
/usr/lib/systemd/system/      # 软件包安装的默认单元
$ ls /etc/systemd/system/ | head -15
basic.target.wants
chronyd.service
cloud-final.service.wants
cloud-init.target.wants
dbus-org.freedesktop.ModemManager1.service
dbus-org.freedesktop.resolve1.service
dbus-org.freedesktop.thermald.service
dbus-org.freedesktop.timesync1.service
display-manager.service.wants
emergency.target.wants
final.target.wants
getty.target.wants
graphical.target.wants
hibernate.target.wants
hybrid-sleep.target.wants

三、systemctl服务管理

# 启动/停止/重启
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo systemctl reload nginx     # 重载配置(不中断服务)

# 开机自启
sudo systemctl enable nginx
sudo systemctl disable nginx
sudo systemctl enable --now nginx  # 启用并立即启动

# 查看状态
systemctl status nginx
systemctl is-active nginx
systemctl is-enabled nginx

3.1 查看服务列表

$ systemctl list-units --type=service --state=running | head -15
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  chrony.service              loaded active running chrony, an NTP client/server
  containerd.service          loaded active running containerd container runtime
  cron.service                loaded active running Regular background program processing daemon
  dbus.service                loaded active running D-Bus System Message Bus
  docker.service              loaded active running Docker Application Container Engine
  getty@tty1.service          loaded active running Getty on tty1
  ModemManager.service        loaded active running Modem Manager
  multipathd.service          loaded active running Device-Mapper Multipath Device Controller
  networkd-dispatcher.service loaded active running Dispatcher daemon for systemd-networkd
  nginx.service               loaded active running A high performance web server and a reverse proxy server
  polkit.service              loaded active running Authorization Manager
  rc-local.service            loaded active running /etc/rc.local Compatibility
  rsyslog.service             loaded active running System Logging Service
  serial-getty@ttyS0.service  loaded active running Serial Getty on ttyS0

3.2 运行级别(Target)

$ systemctl get-default
graphical.target
TargetSysV级别说明
poweroff.target0关机
rescue.target1救援模式
multi-user.target3多用户命令行
graphical.target5图形界面
reboot.target6重启

四、编写Service Unit文件

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Service
After=network.target mysql.service
Wants=mysql.service

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/start.sh
ExecStop=/opt/myapp/bin/stop.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

📋 Service Type类型

类型说明
simple默认,主进程不fork
forking传统守护进程,fork后父进程退出
oneshot一次性任务,配合RemainAfterExit=yes
notify进程通过sd_notify通知就绪
idle等所有任务完成后再启动

4.1 依赖关系

指令强依赖说明
Requires依赖必须成功
Wants依赖最好成功
AfterN/A在依赖之后启动
BeforeN/A在依赖之前启动
ConflictsN/A互斥
BindsTo依赖停则本单元也停
# 修改单元文件后必须重载
sudo systemctl daemon-reload
sudo systemctl restart myapp

五、journalctl日志查询

$ journalctl -b -n 10 --no-pager
May 19 21:55:01 VM-4-3-ubuntu CRON[602221]: pam_unix(cron:session): session closed for user root
May 19 21:55:01 VM-4-3-ubuntu CRON[602219]: pam_unix(cron:session): session closed for user root
May 19 21:55:01 VM-4-3-ubuntu CRON[602220]: pam_unix(cron:session): session closed for user root
May 19 21:55:13 VM-4-3-ubuntu node[544551]: 2026-05-19T21:55:13.722+08:00 [diagnostic] stalled session: sessionId=34fc3f41-76d1-453f-9eb4-c6b8785c14b5 sessionKey=agent:main:subagent:6830370a-aa0e-488e-a6f5-2b7f537e695d state=processing age=1482s queueDepth=0 reason=active_work_without_progress classification=stalled_agent_run activeWorkKind=model_call lastProgress=model_call:started lastProgressAge=325s recovery=none
May 19 21:55:38 VM-4-3-ubuntu sshd[602480]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=195.161.114.163  user=root
May 19 21:55:39 VM-4-3-ubuntu sshd[602480]: Failed password for root from 195.161.114.163 port 57856 ssh2
May 19 21:55:43 VM-4-3-ubuntu node[544551]: 2026-05-19T21:55:43.722+08:00 [diagnostic] stalled session: sessionId=34fc3f41-76d1-453f-9eb4-c6b8785c14b5 sessionKey=agent:main:subagent:6830370a-aa0e-488e-a6f5-2b7f537e695d state=processing age=1512s queueDepth=0 reason=active_work_without_progress classification=stalled_agent_run activeWorkKind=model_call lastProgress=model_call:started lastProgressAge=355s recovery=none
May 19 21:56:01 VM-4-3-ubuntu CRON[602688]: pam_unix(cron:session): session opened for user root(uid=0) by root(uid=0)
May 19 21:56:01 VM-4-3-ubuntu CRON[602689]: (root) CMD (flock -xn /tmp/stargate.lock -c '/usr/local/qcloud/stargate/admin/start.sh > /dev/null 2>&1 &')
May 19 21:56:01 VM-4-3-ubuntu CRON[602688]: pam_unix(cron:session): session closed for user root
# 常用查询
journalctl -b                    # 本次启动日志
journalctl -b -1                 # 上次启动日志
journalctl -u nginx              # nginx服务日志
journalctl -u nginx --since today
journalctl -p err                # 错误级别及以上
journalctl -f                    # 实时跟踪
journalctl --disk-usage          # 日志磁盘占用

六、启动性能分析

$ systemd-analyze
Startup finished in 3.087s (kernel) + 17.240s (userspace) = 20.327s 
graphical.target reached after 16.489s in userspace.
$ systemd-analyze blame | head -10
7.047s apt-daily-upgrade.service
3.554s rc-local.service
3.304s cloud-init-local.service
3.002s systemd-journal-flush.service
2.877s snapd.seeded.service
2.685s docker.service
2.664s snapd.service
2.357s apport.service
2.133s containerd.service
1.961s systemd-networkd-wait-online.service

七、systemd高级功能

7.1 Socket激活

按需启动服务:当有连接到达时才启动服务进程,节省资源。

# myapp.socket
[Unit]
Description=MyApp Socket

[Socket]
ListenStream=8080

[Install]
WantedBy=sockets.target

7.2 Timer定时任务

# myapp.timer
[Unit]
Description=Run MyApp daily

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

7.3 临时修改服务参数

# 使用systemctl edit覆盖特定参数
sudo systemctl edit myapp
# 自动创建 /etc/systemd/system/myapp.service.d/override.conf
# [Service]
# LimitNOFILE=100000
# Environment=DEBUG=true

sudo systemctl daemon-reload
sudo systemctl restart myapp

八、故障排查

❌ 问题:服务启动失败

systemctl status myapp -l
journalctl -u myapp -n 50 --no-pager
systemctl cat myapp
systemd-analyze verify /etc/systemd/system/myapp.service

九、练习

📝 创建自定义服务

sudo tee /opt/hello.sh <<'EOF'
#!/bin/bash
while true; do
    echo "Tue May 19 09:56:13 PM CST 2026: Hello from myapp"
    sleep 5
done
EOF
sudo chmod +x /opt/hello.sh

sudo tee /etc/systemd/system/hello.service <<'EOF'
[Unit]
Description=Hello World Service
After=network.target

[Service]
Type=simple
ExecStart=/opt/hello.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now hello
systemctl status hello
journalctl -u hello -n 10

# 清理
sudo systemctl disable --now hello
sudo rm /etc/systemd/system/hello.service /opt/hello.sh
sudo systemctl daemon-reload
🏆

成就解锁:服务管理大师

✅ 理解systemd架构与Unit类型

✅ 掌握systemctl服务管理

✅ 学会编写Service Unit文件

✅ 掌握journalctl日志查询

✅ 了解systemd-analyze性能分析