10. 服务管理与进程控制
本章介绍 RHEL 9 的 systemd 服务管理、进程控制与 journal 日志管理。systemd 是 RHEL 9 的默认初始化系统与服务管理器,所有服务的启动、停止、自启配置与资源控制均通过它完成。掌握本章是后续安全加固、内核管理与性能优化的直接前提。
10.1 前提条件
- 已完成第一阶段全部配置(第 1–9 章)。
- 通过 SecureCRT(SSH 端口 2222)以
ops用户、密钥认证方式登录192.168.1.100,执行sudo -i切换至 root 环境。 - EPEL 仓库已启用(第 7 章)。
10.2 systemd 基础与服务管理
10.2.1 服务生命周期管理
# 启动 / 停止 / 重启 / 重载配置
systemctl start sshd
systemctl stop sshd
systemctl restart sshd
systemctl reload sshd # 不中断进程,仅重载配置(服务需支持)
# 开机自启管理
systemctl enable sshd # 设置开机自启
systemctl disable sshd # 取消开机自启
systemctl enable --now sshd # 启用并立即启动(最常用)
# 状态查询
systemctl status sshd # 详细状态(含最近日志)
systemctl is-active sshd # 是否运行中(脚本判断用)
systemctl is-enabled sshd # 是否开机自启
10.2.2 批量查看服务状态
# 查看所有运行中的服务
systemctl list-units --type=service --state=running
# 查看所有已失败的 unit(上线前必查)
systemctl list-units --state=failed
# 查看某服务的完整依赖关系
systemctl list-dependencies sshd
检查点
systemctl is-active sshd 返回 active;systemctl is-enabled sshd 返回 enabled。
10.3 运行目标(Target)管理
systemd target 是 SysV runlevel 的现代替代,控制系统启动到哪个功能级别。
# 查看当前默认 target
systemctl get-default
# 生产服务器标准设置(命令行多用户模式,不启动图形界面)
systemctl set-default multi-user.target
# 临时切换 target(不改变默认值)
systemctl isolate multi-user.target
常用 target 对应关系:
| target | SysV runlevel | 用途 |
|---|---|---|
poweroff.target |
0 | 关机 |
rescue.target |
1 | 单用户救援模式 |
multi-user.target |
3 | 多用户命令行(生产标准) |
graphical.target |
5 | 图形界面 |
reboot.target |
6 | 重启 |
生产服务器建议
生产服务器应将默认 target 设置为 multi-user.target,不运行图形界面,减少资源占用和攻击面。安装时已选择 Server with GUI 仅用于实验便利,实际部署可切换为命令行模式。
10.4 创建自定义 systemd 服务
以创建一个简单的监控脚本服务为例,演示完整流程。
10.4.1 准备脚本
tee /usr/local/bin/linuxdc-monitor.sh << 'EOF'
#!/bin/bash
# 简单系统监控示例脚本
while true; do
echo "$(date) | Load: $(uptime | awk -F'load average:' '{print $2}')" \
>> /var/log/linuxdc-monitor.log
sleep 60
done
EOF
chmod +x /usr/local/bin/linuxdc-monitor.sh
10.4.2 创建 Unit 文件
tee /etc/systemd/system/linuxdc-monitor.service << 'EOF'
[Unit]
Description=LinuxDC System Monitor
Documentation=https://linuxdc.com
After=network.target
Wants=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/linuxdc-monitor.sh
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
# 安全限制
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/log
[Install]
WantedBy=multi-user.target
EOF
关键字段说明:
| 字段 | 说明 |
|---|---|
After=network.target |
在网络就绪后再启动 |
Type=simple |
主进程即服务进程(最常用类型) |
Restart=on-failure |
进程异常退出时自动重启 |
RestartSec=10 |
重启前等待 10 秒 |
NoNewPrivileges=true |
禁止进程获取额外权限 |
ProtectSystem=strict |
以只读方式挂载系统目录 |
10.4.3 启用并验证服务
# 重载 systemd 配置(新增或修改 unit 文件后必须执行)
systemctl daemon-reload
# 启用并启动
systemctl enable --now linuxdc-monitor
# 验证
systemctl status linuxdc-monitor
journalctl -u linuxdc-monitor -f
检查点
systemctl status linuxdc-monitor 显示 active (running);/var/log/linuxdc-monitor.log 有内容写入。
10.4.4 修改已有 Unit 文件
生产中不建议直接修改 /lib/systemd/system/ 下的原始 unit 文件(包升级会覆盖)。使用 drop-in 文件覆盖特定参数:
# 为 sshd 创建 drop-in 配置(覆盖部分参数)
systemctl edit sshd
# 编辑器打开 /etc/systemd/system/sshd.service.d/override.conf
# 示例:调整重启策略
# [Service]
# Restart=always
# RestartSec=5
10.5 进程管理
10.5.1 进程查看
# 静态快照
ps aux # 所有进程(BSD 风格)
ps -ef --forest # 树形结构,显示父子关系
# 按资源排序(快速定位问题进程)
ps aux --sort=-%cpu | head -10 # 按 CPU 使用率降序
ps aux --sort=-%mem | head -10 # 按内存使用量降序
# 按名称查找进程 PID
pgrep -l sshd
pgrep -la chronyd # 显示完整命令行
# 交互式监控
top # 按 M 内存排序,P CPU 排序,q 退出
dnf install -y htop
htop # 增强版,支持鼠标操作
10.5.2 进程终止
# 优雅终止(发送 SIGTERM,进程有机会清理资源)
kill <PID>
kill -15 <PID> # 等同于上面
# 强制终止(发送 SIGKILL,进程无法拦截,谨慎使用)
kill -9 <PID>
# 按名称终止
pkill sshd # 终止所有名为 sshd 的进程
pkill -f "python3 /opt/app" # 按完整命令行模式匹配
killall httpd # 终止所有同名进程
kill -9 的使用时机
kill -9 会强制终止进程而不给予清理机会,可能导致数据损坏或文件锁残留。应先尝试 kill(SIGTERM),等待数秒后若进程仍未退出再使用 kill -9。
10.5.3 调整进程优先级
nice 值范围:-20(最高优先级)到 19(最低优先级),默认 0。
# 以低优先级运行耗时任务(避免影响生产业务)
nice -n 15 tar -czf /backup/data.tar.gz /opt/data
# 调整正在运行进程的优先级
renice -n 10 -p <PID> # 降低优先级(普通用户可执行)
renice -n -5 -p <PID> # 提升优先级(需 root)
# 查看进程优先级
ps -eo pid,ni,comm --sort=ni | head -20
10.5.4 后台任务管理
# 后台运行(& 放到后台,nohup 防止 Shell 退出时终止)
nohup /opt/scripts/backup.sh > /var/log/backup.log 2>&1 &
# 查看后台任务
jobs -l
# 将后台任务调到前台
fg %1
# 将前台任务放到后台(先 Ctrl+Z 挂起,再 bg)
bg %1
10.6 journal 日志管理
RHEL 9 使用 systemd journal 作为主要日志系统,所有服务日志统一由 journald 收集。
10.6.1 查看日志
# 查看指定服务的日志
journalctl -u sshd # sshd 全部日志
journalctl -u sshd -f # 实时追踪(等同于 tail -f)
journalctl -u sshd -n 50 # 最近 50 条
# 按时间过滤
journalctl --since "2025-06-01 08:00:00"
journalctl --since "1 hour ago"
journalctl --since today
# 按优先级过滤(emerg/alert/crit/err/warning/notice/info/debug)
journalctl -p err -b # 本次启动的 error 及以上级别日志
journalctl -p warning --since "1 hour ago"
# 查看内核日志
journalctl -k # 等同于 dmesg
journalctl -k --since "30 min ago"
# 查看引导日志
journalctl -b # 本次引导
journalctl -b -1 # 上次引导
journalctl --list-boots # 列出所有引导记录
10.6.2 日志持久化配置
默认情况下 journal 日志存储在内存中(重启丢失),配置持久化到磁盘:
mkdir -p /var/log/journal
systemd-tmpfiles --create --prefix /var/log/journal
vim /etc/systemd/journald.conf
关键配置项:
[Journal]
Storage=persistent # 持久化存储(auto/volatile/persistent/none)
Compress=yes # 压缩日志
SystemMaxUse=2G # 最大占用磁盘空间
SystemKeepFree=500M # 至少保留的磁盘空间
MaxRetentionSec=30day # 日志最长保留时间
应用配置:
systemctl restart systemd-journald
10.6.3 日志清理
# 查看当前日志占用空间
journalctl --disk-usage
# 按时间清理(保留最近 7 天)
journalctl --vacuum-time=7d
# 按大小清理(限制总大小为 500 MB)
journalctl --vacuum-size=500M
# 仅保留最近 5 个引导的日志
journalctl --vacuum-files=5
10.6.4 配置 rsyslog 转发日志
如需将日志转发到集中式日志服务器(如 ELK、Graylog):
vim /etc/rsyslog.conf
在文件末尾添加(TCP 转发更可靠):
# 转发所有日志到集中式服务器
# @@ 表示 TCP;@ 表示 UDP
*.* @@192.168.1.200:514
systemctl restart rsyslog
# 发送测试日志验证转发
logger -t linuxdc "Test log from 192.168.1.100"
生产环境建议
生产环境推荐使用 TCP(@@)而非 UDP(@)转发日志,TCP 有重传机制,日志不易丢失。集中式日志是等保合规的基本要求之一。
10.7 常见问题与排查
| 问题现象 | 排查步骤 |
|---|---|
| 服务启动失败 | systemctl status <service> 看末尾错误;journalctl -u <service> -n 50 查详细日志 |
| 自定义服务不自启 | 确认执行了 systemctl enable;确认 [Install] 节中有 WantedBy=multi-user.target |
| daemon-reload 后服务仍未更新 | 确认 unit 文件语法正确:systemd-analyze verify /etc/systemd/system/<service>.service |
| 日志磁盘占满 | 立即执行 journalctl --vacuum-size=200M;然后配置 SystemMaxUse |
# 验证 unit 文件语法
systemd-analyze verify /etc/systemd/system/linuxdc-monitor.service
# 查看 systemd 启动耗时分析
systemd-analyze blame | head -20
10.8 实践任务
- 登录
linuxdc(SecureCRT 端口 2222,ops用户,密钥认证,sudo -i切换 root)。 - 查看当前失败的 unit:
systemctl list-units --state=failed。 - 将系统默认 target 改为
multi-user.target并验证。 - 按照 10.4 节,完整创建并启用
linuxdc-monitor服务,验证其运行状态。 -
查看
sshd最近 1 小时的日志,并过滤出 warning 及以上级别:journalctl -u sshd --since "1 hour ago" -p warning -
查看 journal 日志占用空间,配置持久化,并执行一次按时间清理。
10.9 自测问题
Q1:systemctl reload 与 systemctl restart 有什么区别?
reload 向进程发送信号(通常是 SIGHUP),让其重新读取配置文件,不中断进程,连接不会中断(如 nginx reload);restart 先停止进程再重新启动,会中断连接。配置变更时优先使用 reload,仅在 reload 不支持时才使用 restart。
Q2:新建 unit 文件后为什么必须执行 systemctl daemon-reload?
systemd 在启动时将 unit 文件解析并缓存到内存中。新增或修改 unit 文件后,内存缓存不会自动更新。daemon-reload 命令强制 systemd 重新扫描并加载所有 unit 文件,使变更生效。
Q3:journal 日志默认重启后丢失,如何确认是否已配置持久化?
执行 ls /var/log/journal/,若目录存在且有内容,说明已持久化;若目录不存在或为空,日志仅存储在 /run/log/journal/(内存,重启丢失)。可通过 journalctl --disk-usage 查看当前占用情况。
10.10 章节总结
本章介绍了 RHEL 9 systemd 服务管理的核心操作:服务生命周期控制、运行目标管理、自定义 service unit 创建(含安全限制字段)、进程查看与终止,以及 journal 日志的查询、持久化与清理。这些是运维日常工作的高频操作,也是后续内核管理与安全加固的基础工具。