拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RH124第9章精讲:systemd服务管理与故障排查实战

RH124第9章精讲:systemd服务管理与故障排查实战

1. 别小看这一章:服务管理是 RH124 里最值钱的基础功

我这些年带过不少准备 RHCSA 的学员,很多人一翻开 RH124 教材就急着去看文件权限、用户管理这些章节,觉得“控制服务和守护进程”无非就是几条 systemctl 命令,考试前背一背就行。但实际到了考场,或者真到生产环境里排查问题时,栽跟头最多的恰恰是这一章。

为什么?因为服务管理不是“记住命令”就能过关的,它考验的是你对系统启动流程、进程生命周期、依赖关系、日志定位这套完整逻辑的理解。RH124 第 9 章“控制服务和守护进程”安排在这个位置,绝不是随便排的——前面的章节教你认路、开机器、摸文件,从这一章开始,你才真正让 Linux 系统“跑起来干活”。

守护进程这个概念,我会跟学员打一个比方:守护进程就像是饭馆后厨里一直在岗的师傅。你点菜(输入命令),师傅们各自负责自己的灶台——有的是蒸饭的,有的是炒菜的,有的是洗碗的——他们不等着你叫才开工,而是系统一开张就各自在位。systemd 就是那个后厨总管,负责点名、安排排班、盯谁在偷懒、谁累垮了把它扶起来。理解了这个场景,后面所有 systemctl 操作都不会觉得抽象。

这篇文章我会完全围绕 RH124 第 9 章的知识点,按问答题的节奏把守护进程与服务的概念、systemd 的核心管理命令、单元文件结构、target 机制、日志排查这些内容全部拆开揉碎。适合正在准备 RHCSA 考试的人,也适合刚入行、想搞明白服务为什么起不来、怎么设置开机自启的运维新手。

2. 守护进程与服务:先搞清楚你管的东西到底是什么

2.1 守护进程不是“病毒”,是系统里的“老黄牛”

很多零基础学员第一次听到 daemon 这个词,脑子里会浮现出电影里的黑客程序。其实守护进程恰恰是这个星球上最勤劳的程序形态。它的特征是:长期驻留内存、不占用终端、在后台默默干活。

举几个你天天都在接触的例子。你 ssh 登录一台服务器,sshd 这个服务其实早就跑着了,它守候在 22 号端口上,来一个连接就“生”一个会话进程来处理;你访问网页,httpd 或 nginx 进程在后台常驻;你发邮件,postfix 进程监听 25 端口。这些服务如果不在后台,我们一关终端它们就退出,那服务器啥也干不成。

区分几个术语很重要:守护进程(daemon)、服务(service)、进程(process)。按照 RH124 的口径,守护进程就是后台运行的进程,它们通常以“d”结尾,比如 systemd、sshd、httpd 里的 httpd 的“d”就是 daemon 的意思。服务是一个更宽泛的概念,一个服务可能包含多个进程,比如 Apache 服务有主进程和 worker 进程。而我们平时用 systemctl 管理的,就是从服务的视角去控制系统里的一组进程。

2.2 systemd 凭什么取代了 SysVinit

RH124 第 9 章会简单提一句历史:RHEL 7 开始,系统初始化和服务管理全面切换到 systemd,取代了老旧的 SysVinit。这里要理解的是 systemd 的几个关键优势,而不是死记年份。

老 SysVinit 时代,服务管理靠脚本,启动服务时必须等上一个脚本完全结束才能启动下一个,哪怕两个服务之间没有任何依赖关系,也要排队,系统启动速度自然慢。systemd 的设计思路改成了并行启动:只要服务之间没有明确依赖,就同时拉起。另外,systemd 引入了“按需启动”机制,socket 激活等高级玩法让一些不常用的服务不用着急启动,等有人访问时再拉起来就行。这对于服务器开机速度的提升是肉眼可见的。

还记得前面那个后厨总管比喻吗?SysVinit 像是只有一个厨师长,所有菜必须按顺序做;systemd 是多个厨师并行操作,还能实时监控哪个灶台熄火了,立刻重新点火。

注意:RHCSA 考试不要求你会写 unit 文件,但要求你能看懂 unit 文件、能判断服务当前状态、能修改配置让服务按你期望的方式运行。不要上来就啃长篇配置,先把管理命令玩熟。

2.3 服务状态有几种,别被 systemctl 的输出搞晕

我观察到一个普遍现象:学员敲 systemctl status 命令后,看到一大片输出就懵了,不知道该看哪一行。

systemctl status sshd

输出关键要看三块内容:

  • 第一行是单元描述和加载情况,含 show 状态。比如Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; preset: enabled)里面的enabled表示开机自启。
  • 第二行是 Active 状态,这是最核心的。active (running)是正在运行,active (exited)是运行过但当前没有进程驻留(比如一次性任务),inactive (dead)就是没在跑。
  • 后面几行是最近日志,用来排查退出原因。

我发现一个很容易被忽略的重点:loaded不等于active。一个服务已经被 systemd 读取了配置,这只能说明“系统知道有这号人”,至于这个人现在是在工位上干活还是回家睡觉了,要看active。这两个概念混淆是新手排错时经常卡壳的地方。

3. systemctl:你与系统服务之间的对话窗口

3.1 最常用的五个子命令,先形成肌肉记忆

RH124 第 9 章明确要求掌握 systemctl 的常用子命令。课堂上我要求学员先练出肌肉记忆的,就下面这几个:

systemctl start 服务名 # 立即启动,不设开机自启 systemctl stop 服务名 # 立即停止 systemctl restart 服务名 # 停止后重新启动,常用于配置修改后 systemctl reload 服务名 # 不中断服务,重新加载配置文件 systemctl enable 服务名 # 设置开机自启 systemctl disable 服务名 # 取消开机自启

这里必须解释清楚restart和reload的区别,这是考试喜欢挖坑的地方,也是生产环境操作的“生死线”。restart是粗暴地把进程全部干掉再拉起来,服务会有几十毫秒到几秒的不可用时间,但如果程序本身不冲突,往往能解决很多运行异常。reload是温和地通知进程“配置文件改了,你重新读一遍”,进程 pid 不变,连接不中断。像 nginx、sshd 这样的服务,改完配置优先考虑 reload,不要动不动就 restart,否则线上用户会感受到明显卡顿。

还有一对容易混淆的组合:start和enable是两个独立操作,一个只管当前,一个只管开机。很多人以为启动了服务就等于开机自启了,这是错的。你start httpd后服务器重启,httpd 仍然是死的,除非你执行过enable httpd。生产环境里常见的问题——服务器重启后某个服务没起来——根因往往就是当年部署时只 start 没 enable。

systemctl enable --now httpd # 开机自启 + 立即启动一步完成

这是我强烈推荐的口诀式命令,--now参数把“当前启动”和“开机自启”捆绑执行,省掉一次手工 start,也少了一个遗忘点。

3.2 查看状态别只看“活没活”,还要看“想不想活”

systemctl status 服务名 systemctl is-active 服务名 # 只回显 active/inactive/failed systemctl is-enabled 服务名 # 只回显 enabled/disabled

status 命令适合人类读,一大片输出里什么都有;is-active 和 is-enabled 适合脚本判断,输出干净利落。写监控脚本时别去 grep status 的输出,直接用这两个命令,省心得多。

还有几个查看类命令要掌握:

  • systemctl list-units --type service --state running:列出所有正在运行的服务单元。
  • systemctl list-unit-files --type service:列出所有服务单元文件及是否 enable。
  • systemctl list-dependencies 服务名:查看服务的依赖树,排错时很好用。

3.3 一个典型的完整操作流程:搭个 HTTP 服务

把前面命令串起来走一遍,你会对整体逻辑更清晰。假设现在要在一台 RHEL 9 上部署 httpd:

dnf install -y httpd systemctl start httpd systemctl enable httpd systemctl status httpd

执行完 status 后,大概率你会看到active (running),就放心了。但我要提醒一句:systemctl status 显示的“running”只代表进程活着,不代表业务可用。极端情况下 Apache 配置写错了,进程照样能跑起来,但它监听不到真正的端口。所以判断服务是否真正可用,一定要配合端口检查。

ss -tlnp | grep 80 curl http://localhost

这个思路会一直伴随你的运维生涯:服务管理命令管的是“进程状态”,业务可用性要靠“端口/接口探测”来确认。

4. 单元文件与 target:理解 systemd 的“规矩”和“关卡”

4.1 单元文件优先级:同一份配置,三个地方放,听谁的

systemd 里面被管理的对象都叫“单元(unit)”,服务只是其中一种。单元文件存放在三个层级,优先级从高到低:

目录来源优先级
/etc/systemd/system管理员自定义或覆盖最高
/run/systemd/system运行时生成的临时配置高
/usr/lib/systemd/system软件包安装时自带低

这个设计非常巧妙。软件包自带的默认配置放在 /usr/lib/systemd/system 里,系统升级时可能被覆盖,你不能去改它;管理员的自定义放在 /etc/systemd/system 里,哪怕软件重装也不会被动。生产环境里改服务配置,正确姿势是在 /etc/systemd/system 下建一个 override 文件(同名 but 带 .d 后缀的目录),而不是直接改 /usr/lib 下的原文件。

直接改 /usr/lib 下的文件,我见过太多人这么干,表面上看也能生效,但一旦软件包更新,你的修改就被新版本覆盖,而且不会有人告诉你。想优雅地改某个服务的参数,推荐做法是:

mkdir -p /etc/systemd/system/sshd.service.d cat > /etc/systemd/system/sshd.service.d/override.conf <<'EOF' [Service] Restart=always RestartSec=3s EOF systemctl daemon-reload

这样 sshd 服务一旦异常退出,systemd 会在 3 秒后自动拉起它。至于为什么不直接在原来的 unit 文件里加Restart=always——上面表格已经解释了,那个文件归软件包管,轮不到你改。

4.2 剖析一个服务单元文件的骨架

拿 httpd 的单元文件举例(RHEL 9 上可以看到),核心结构如下:

[Unit] Description=The Apache HTTP Server Wants=systemd-networkd.service After=network.target [Service] Type=notify ExecStart=/usr/sbin/httpd -DFOREGROUND ExecReload=/usr/sbin/httpd -k graceful Restart=on-failure [Install] WantedBy=multi-user.target

课堂上我会让学员按三段来记:[Unit]段落记录描述和依赖关系,[Service]段落定义怎么启动、怎么重启、以什么类型运行,[Install]段落定义 enable 时挂到哪个 target 下面。

After=和Wants=要区分。Wants=是软依赖,能拉起来就拉起,拉不起来不影响本体启动;After=只决定启动顺序,不决定依赖。还有一种是Requires=,这是硬依赖,要求的服务起不来,本体也别想起来。这个差异是考试的重点,也是排查“A 服务明明配置了依赖 B,为什么 B 没启动”时优先怀疑的对象——八成是写成了Wants而不是Requires。

Type=这个参数也值得琢磨。常见的几种:

  • simple:ExecStart 指定的进程就是主进程,立即认为服务启动完成。
  • forking:主进程 fork 出子进程后立即退出,父进程退场,子进程接管(传统 daemon 的做法)。
  • notify:服务进程主动向 systemd 发通知,报告“我准备就绪了”。
  • oneshot:执行完即退出的一次性任务。

判断 Type 对不对,直接影响 systemctl status 显示的状态是否准确。如果 Type 写错,systemd 会误判服务启动完成或一直认为没起来,定位问题时会走弯路。

4.3 target:服务启动的“总开关”

target 在 RH124 里定义为“一组单元的集合”,作用相当于把系统引导过程划分成若干里程碑。你可以理解为关卡节点:系统开机时先到某个 target,激活这个 target 下面的所有服务;然后切换到下一个 target,再激活另一批服务。

最常用的是这几个:

  • multi-user.target:纯字符界面的多用户状态,服务器默认落到这里。
  • graphical.target:带图形界面的状态,等于 multi-user 加上图形登录。
  • reboot.target:重启。
  • poweroff.target:关机。

查看当前系统落到了哪个 target,用:

systemctl get-default

设置默认 target,用:

systemctl set-default multi-user.target

临时切换当前运行级别(不需要重启),用:

systemctl isolate multi-user.target

isolate是那个最霸道的命令:它会停掉所有不属于目标的单元。所以对服务器做隔离操作前,一定确认你自己有控制台访问能力,不然可能把自己锁在外面。另外在 RH124 对应的 RHCSA 考试中,图形界面机器上改默认 target 到字符界面也是经典操作,逻辑就是上面两行命令。

每个服务单元文件里的[Install]段写的WantedBy=multi-user.target,就是告诉 systemd:“当你把我 enable 时,把我挂到 multi-user.target 的 Wants 列表里”。这样开机进入 multi-user 时,系统会自动拉起这个服务。所以 enable 的本质动作是建了一个软链接,从/etc/systemd/system/multi-user.target.wants/指到实际的 unit 文件。

4.4 修改了单元文件,必须重载

这是一个极其常见的坑:你改了 /etc/systemd/system 下的某服务配置,然后 systemctl restart 服务,发现配置根本没生效。原因很简单——systemd 还在用内存里缓存的旧配置。

改完任何 unit 文件或 override 文件后,必须执行:

systemctl daemon-reload

这个命令让 systemd 重新读取磁盘上的 unit 文件。你在很多部署脚本里看到的“restart 之前先 daemon-reload”,不是说每次都要做,但只要你加了、删了、改了 unit 文件,哪怕只是改了个注释,也建议执行一次,成本极低,收益是避免“改了好像没改”的诡异问题。

5. 日志管理:服务出问题,第一步不是猜,是查日志

5.1 journald:集中式日志的集散中心

RHEL 7 之后,系统的日志收集统一交给了 systemd-journald。它把内核日志、各类服务的标准输出、标准错误、syslog 内容全部收拢起来,按服务单元打标签归档。查询服务日志有天然的优势——你根本不用知道日志文件写在哪个路径,一条命令全解决:

journalctl -u sshd

这条命令显示 sshd 的全部日志。平时最常用的加料版:

  • journalctl -u sshd -f:持续跟踪(类似 tail -f),调试时开着很爽。
  • journalctl -u sshd --since "1 hour ago":只看最近一小时的日志。
  • journalctl -u sshd --since today --until "2025-01-01 00:00":按时间区间过滤。
  • journalctl -u sshd -p err:只看 error 级别以上的日志。

配合 -p 可以迅速过滤出关键错误,不用在一堆 info 日志里人工翻。

5.2 从日志反推服务启动失败的原因

我让学员做故障演练时,最经典的一幕是:某个服务起不来,学员先懵三秒,然后开始瞎猜,什么端口冲突了、防火墙挡了、配置文件错了。正确的路径是:先看状态,再看日志,最后才动手。

systemctl status httpd journalctl -u httpd -n 50

status输出末尾会自带最近几条日志,journalctl -n 50拉最近 50 条。这两步走完,八成的原因已经浮出水面了。

举一个实际排错例子:某次学员把 httpd 的 DocumentRoot 目录权限改成了 700,然后 restart 服务,状态变成 failed。journalctl 里明确写着类似Permission denied的报错,因为 Apache 的 worker 进程以 apache 用户身份运行,进不了 root 才拥有的目录。你如果不知道 apache 用户需要什么权限,看到这个日志再结合这个小知识点,马上就能对症下药。

5.3 日志持久化:重启不丢数据

journald 默认把日志存在内存里,服务器一重启,之前的日志全没了。生产环境想留痕,必须开启持久化存储:

mkdir -p /var/log/journal systemctl restart systemd-journald

目录存在,journald 自动切换为持久模式,日志会写到磁盘。RH124 考试范围里不深究这个,但作为运维基本功,建议你现在就知道。不然哪次线上出问题,重启以后想复盘,发现日志干干净净一片空白,那才是真叫天天不应。

6. 常见故障与排查实录:那些年我们踩过的 systemd 的坑

6.1 服务状态是 failed,但日志里没有明显报错

这类问题往往和“环境”有关。unit 文件里的Environment=或环境脚本设置有问题,服务进程启动时报错,但报错信息没输出到 journald,看起来就像“没理由的失败”。

排查思路是:手动用服务进程的实际身份运行一遍启动命令。比如 httpd 起不来但日志只有一句failed,你可以:

sudo -u apache /usr/sbin/httpd -DFOREGROUND

直接在终端跑一遍,把错误逼出来。很多时候报错信息会直接打在终端上,远比日志里的概括性描述来得具体。这招在排查 systemd 单元启动类问题时,效率高得惊人。

6.2 systemd 时间同步问题

有一次学员在做实验室时发现,journalctl --since today一片空白,但明明刚才还有日志刷出来。一查系统时间,发现 VM 的时钟严重偏离真实时间,日志都带着一个“未来时间戳”,所以按今天过滤时什么都捞不着。

这类问题在生产环境的虚拟机上很容易遇到,尤其是从快照恢复的老虚拟机。解决思路是先校准时间,再看日志时间轴是否正常。虽然这一章没有专门讲 chrony,但日志排查时时间同步的概念一定会撞上,提前有个意识能少走弯路。

6.3 服务被 killed,是内存被 OOM 干掉了

你执行 systemctl status 看到进程状态是active (running),但日志里出现Killed字样。这通常是进程因内存不足被内核 OOM Killer 选中干掉了。你会在 journalctl 或 /var/log/messages 里看到内核相关记录。

排查思路:

  • 确认进程实际是不是活着:ps -ef | grep 服务名看 pid 是否还在。
  • 看内存余量:free -h,如果 available 很低,大概率是内存压力问题。
  • 用systemctl status里的 Main PID 和ps -o etime对一下,如果进程是从失败后重新拉起的,可能已经经过了两次重启循环。

这类“状态看着是活,其实已经死而复生”的情况,是实际生产中最难察觉的伪健康。这也是为什么监控脚本不能只看 systemctl is-active,一定要结合业务端口和进程存活时长判断。

6.4 开机启动顺序“莫名其妙”

如果服务 A 启动依赖服务 B 已经把某个端口准备好,但 A 是在 B 之前拉起的,就会失败。检查写法时记住:After=控制顺序,它写在 A 的 [Unit] 段里。如果 A 写了After=B,systemd 会等 B 启动完再启动 A。

但After=不等同于依赖关系,如果你还写了Wants=B,那 B 挂了 A 照样起。希望 B 挂掉后 A 也别起来,需要Requires=B。明确需求量级:光是“先后顺序”用 After;“一起活、一起死”用 Requires。不要想当然地写。

6.5 配置文件有语法错误,服务还能起?

有一种比较隐蔽的情况:服务配置错了,但进程能跑。比如 sshd_config 里写了一个无效参数,sshd 启动时会以“静默忽略”的方式继续运行,并不报错。systemctl status 显示 active,但你的某项功能死活不对。这时候只有读日志或手动运行主程序才能看到真实的 warning。

这类问题比较考验经验,我平时教学时反复跟学员强调:systemctl 管理的是“进程起没起来”,不是“配置对没对”。进程活着代表它按当前配置能自洽运行,不保证配置符合你的预期。排查配置类问题,直接调出日志,或者手动运行并按需求加-t等参数做验证。

7. 实操测试:自己动手做一遍,比看十遍记住得更牢

RH124 第 9 章的知识点很适合用一套小实验收尾。以下实验建议你在虚拟机里完整走一遍,全部做完大约需要二十分钟,但对命令和理解会有质的提升。

# 1. 安装 httpd dnf install -y httpd # 2. 启动并设置自启 systemctl start httpd systemctl enable --now httpd # 3. 确认状态 systemctl status httpd # 4. 查看 httpd 的单元文件 systemctl cat httpd # 5. 查看 httpd 的依赖 systemctl list-dependencies httpd # 6. 测试临时关闭自启再恢复 systemctl disable httpd systemctl list-unit-files | grep httpd # 应该是 disabled systemctl enable httpd # 7. 修改配置前先备份,修改后 reload cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak systemctl reload sshd # 8. 看日志 journalctl -u httpd -n 20 # 9. 设默认 target 为字符界面再改回来 systemctl set-default multi-user.target systemctl set-default graphical.target

做第 7 步时注意,reload 对 sshd 的安全性:如果你当前正通过 ssh 连接,且 sshd_config 改错了,reload 不会断开现有连接,但新连接会连不上。所以改完立刻新开一个终端测一下能不能登录,能登录再继续用,不能就赶紧用现有连接把备份文件还原。

我还建议你把 httpd 的 unit 文件复制到 /etc/systemd/system/ 下,改改Restart=always,然后 kill 掉主进程,观察 systemd 在几秒内自动把它拉起来。

kill -9 $(pgrep httpd | head -1) systemctl status 服务名 # 过几秒再看,状态是 active

这比单纯敲命令更能建立对“守护进程”这个词的体感——你现在亲手杀掉了它,它又活了,这就是 systemd 守护进程的真正含义。

8. 经验篇:RH124 第 9 章,你该怎么学才算真学透

判断一个人是不是真掌握这一章,我通常看三个维度:

第一,会不会根据“服务起不来”这一个现象,梳理出排查顺序。顺序是:状态 → 日志 → 配置 → 端口 → 测试。这个顺序不是教材里写的,是生产环境压出来的经验,建议你自己写一个 checklist 贴在工位上。

第二,会不会意识到 status 输出里的“Loaded”和“Active”是两回事。很多人一看 loaded 就默认服务没问题,这是最大的盲区。

第三,会不会合理选择 restart 和 reload。改配置先 reload,程序异常再 restart,这不仅是命令选择问题,更是对线上业务的负责态度。我见过因为图省事一律 restart 的服务,把线上会话全部打断,用户在群里骂了半天。从那天起我就形成了一个习惯:任何服务配置变更,第一选择永远是 reload。

另外,学这一章时建议打开一个免费的系统虚拟机一起操作,不要只看不练。键盘敲命令和眼睛看教程完全是两回事,敲过一遍systemctl enable --now后,你的肌肉记忆会帮你把它刻在脑子里。

RH124 第 9 章是整个 RHCSA 认证体系里服务和进程管理的地基。后面你会学网络配置、存储管理、SELinux,这些内容多多少少都要和服务打交道。把 systemd 的逻辑吃透,你后面遇到的多半只是“命令变化”,而不是“思路重来”。

最后分享一个小技巧:遇到不认识的新服务,先执行systemctl cat 服务名看它的 unit 文件,再执行journalctl -u 服务名 --since today看它今天的日志。只需要这两条命令,你就大致知道这个服务是干什么的、跑得正不正常。这招在接手一台陌生服务器时特别好用,推荐你用起来。

返回列表