
作为一个常年跟 Linux 打交道、也带过不少新人备考红帽认证的老兵RH124 这套课程我可以说非常熟悉。而“控制服务和守护进程”这一章几乎是整个系统管理的地基不管你是要应付考试还是以后真刀真枪地去管生产服务器systemd 这套东西绕不开。很多初学者在这一章容易犯迷糊主要是概念太多服务、单元、目标、守护进程、会话每个词都认识连在一起就懵了。所以我把这章整理成了一份问答笔记不光是背答案而是把每个知识点背后的“为什么”也讲清楚。这篇内容适合正在备考 RH124 的考生、刚入行的运维以及所有想把 systemd 真正用明白的人。1. systemd 到底在解决什么问题1.1 从 SysVinit 到 systemd为什么非换不可先说背景。RH124 第 9 章的核心对象是 systemd但很多人不知道它之前是什么样。早期 Linux 用的是 SysVinit启动服务靠一串 shell 脚本按序号执行S01xxx、S02xxx 这种。脚本本身没什么问题问题出在启动方式上——串行执行一个一个来一个脚本卡住后面全等着。开机慢、依赖关系混乱、不好并行这是 SysVinit 的硬伤。systemd 的设计目标很明确更快、更可靠、依赖关系更清晰。它把服务、挂载点、设备、定时任务这些统统抽象成“单元”Unit每个单元用一个配置文件描述单元之间可以声明依赖和顺序。systemd 会自己分析依赖图能并行的就并行启动能延迟的就延迟启动。所以现代 Linux 开机速度快systemd 功不可没。从考试角度来看你需要记住的不只是命令而是要建立一套“用 systemd 的思维模式”管理服务用 systemctl管理系统状态用 systemctl isolate 或切换到某个 target查看日志用 journalctl分析启动过程用 systemd-analyze。这套组合拳打下来系统在你眼里就是透明的。1.2 单元类型那么多考试要分清哪些systemd 的单元类型有十几种但 RH124 范围内你主要接触这些service最常打交道的单元代表一个守护进程或服务。target一组单元的集合相当于旧的运行级别概念后面细说。socket代表一个监听套接字可以用来实现按需启动。timer定时器单元替代传统的 cron但比 cron 更精细。mount / automount文件系统挂载点。path监控某个文件或目录变化的单元。考试里最容易混淆的是 service 和 target。记住一句话target 不启动任何进程它只是一个“分组标志”把一堆单元拉进来形成一个可用的系统状态。比如 graphical.target 就是 multi-user.target 加上显示管理器。你问 systemctl get-default 得到的是默认 target而不是“默认服务”这个别搞混。顺便提一个重要细节单元名后面带不带 .service 后缀systemctl 命令在操作 service 类型时可以省略后缀但操作其他类型必须写全。比如 systemctl start sshd 和 systemctl start sshd.service 效果一样但 systemctl start multi-user.target 就不能省略 target。这种小细节考试可能直接考。2. systemctl你每天都要用的“遥控器”2.1 状态管理命令的完整用法systemctl 是管理 systemd 的前台工具命令格式非常统一systemctl [动作] [单元名]。最核心的动作有这些start立即启动一个单元。stop立即停止一个单元。restart先停再启适用于改了配置需要重启生效的场景。reload不中断服务只重新加载配置文件。前提是这个服务支持 reload很多服务都有这个能力。enable设置开机自启。disable取消开机自启。status查看完整状态包括进程、日志、依赖。is-active / is-enabled只看一个结果脚本里常用。初次上手强烈建议多用 status 看输出。它把服务状态、主进程 PID、内存占用、最近日志都打印出来一条命令抵得上以前 ps tail chkconfig 三件套。我教新人的时候常讲status 是“首页”进去之后按需展开。有一点要特别注意restart 和 reload 的区别。restart 会杀掉进程再拉起来适合内核参数、监听端口等启动时才能生效的配置reload 只是让主进程重新读配置文件适合并发连接高、不想断线的场景。如果拿不准服务支持不支持 reload可以看/usr/lib/systemd/system/xxx.service里有没有 ExecReload 字段有就能用。2.2 enable 和 start 的“四象限”逻辑考试里常挖坑的一个点是enable 不等于 startdisable 不等于 stop。它们是两个维度的操作。我用一个四象限来说明状态说明常见场景已 enable 且已 start开机自启且当前正在运行正常生产服务已 enable 但未 start开机自启但当前没运行服务曾经停止但下次开机还会启动未 enable 但已 start当前运行但重启后不启临时测试用的服务未 enable 且未 start完全关闭禁用不用的服务理解这个逻辑后你就明白为什么 systemctl disable 一个正在运行的服务时服务不会立刻停。要彻底停掉必须 disable 加 stop 一起来。实际工作中经常有人只 disable 没 stop导致服务还在跑产生各种奇怪问题。还有一对概念也容易混mask 和 disable。disable 只是取消开机自启服务文件仍然可以被手动 startmask 是彻底屏蔽会把单元链接到 /dev/nullstart 都会失败。什么时候用 mask比如你想绝对防止某个服务被拉起像 systemd 自带的某些服务在你机器上用不到又怕它出幺蛾子直接 mask 掉最干净。2.3 查看开机自启状态一条命令看清所有服务systemctl list-unit-files用来查看所有单元文件的状态会显示每个单元是 enabled、disabled、static 还是 masked。其中 static 比较特殊表示这个单元不能直接 enable只能被其他单元依赖时激活。比如某些服务的 .socket 单元就是 static它们随着 service 一起被启用。这个命令在实际排障时特别好用。新装一台机器想知道哪些服务开了自启直接 systemctl list-unit-files --typeservice 过滤出 service 类型再 grep enabled一目了然。考试中会有一类题给你一堆服务让你判断哪些重启后还会跑本质上就是在考 enable 状态的理解。想要更精确的过滤可以加 --stateenabled 参数systemctl list-unit-files --typeservice --stateenabled。这样输出的就是所有开机自启的服务清单干净利落。3. target从运行级别到系统状态3.1 runlevel 时代的遗留概念老一代 Linux 用 0~6 七个运行级别分别代表关机、单用户、多用户、图形界面、重启等。现代 systemd 用 target 取代了这套体系但为了兼容还是保留了对应关系运行级别target说明0runlevel0.target → poweroff.target关机1runlevel1.target → rescue.target单用户救援模式2runlevel2.target → multi-user.target多用户无图形3runlevel3.target → multi-user.target多用户无图形4runlevel4.target → multi-user.target多用户无图形5runlevel5.target → graphical.target图形界面6runlevel6.target → reboot.target重启注意 2、3、4 都映射到 multi-user.target这是 systemd 故意做的简化。你不需要再纠结“级别 3 和级别 4 有什么区别”在 systemd 世界它们就是同一个东西。考试考查 target 通常以三种形式出现查看当前默认 target、修改默认 target、临时切换 target。前两个用 get-default 和 set-default第三个用 isolate。systemctl isolate multi-user.target 相当于在运行状态下从图形界面切到命令行界面会比 set-default 加 reboot 快得多适合临时操作。3.2 救援模式和紧急模式怎么进rescue.target 是单用户模式会挂载所有文件系统并启动基础服务适合修复系统问题emergency.target 更极端几乎不启动任何服务只给一个 shell适合救砖级的排障。两者的区别可以这么记忆rescue 是“带基础装备进副本”emergency 是“裸装进去”。从实际应用看日常运维进 rescue 的机会不多但考试会考怎么从 GRUB 启动菜单进入这两个模式。方法是编辑内核启动参数在 linux 行末尾加 systemd.unitrescue.target 或 systemd.unitemergency.target。这句话要记住因为默认的启动参数里没有这个选项得自己加。另外还有一个考点临时切换 target 用 systemctl isolate而救援和紧急模式本质上也是 target所以也可以用 isolate 切换。但如果你把系统切到 rescue.target退出后系统会停在命令行不会自动回到图形界面——如果之前是图形环境要手动 systemctl isolate graphical.target或等 reboot。3.3 默认 target 的修改技巧修改默认 target 有两种方式systemctl set-default graphical.target写软链接永久生效。直接编辑 /etc/systemd/system/default.target 软链接。命令方式更安全因为 systemctl 会做校验。查看当前默认systemctl get-default。这几乎是我接手任何一台新机器都会执行的命令先确认开机进图形还是命令行心里有底。我还遇到过一种情况机器装了 GNOME 但默认进命令行用户想改回图形界面。直接 set-default graphical.target 就行。反过来一台服务器不想跑图形界面浪费资源就把默认改成 multi-user.target重启后轻装上阵。考试里可能会给你一个场景让你配“图形开机”实际上就是在考 set-default。4. unit 文件深入服务的心脏4.1 目录分三层优先级谁说了算systemd 的单元文件分布在三个地方优先级从低到高/usr/lib/systemd/system/软件包安装时自带的单元文件。rpm 装的服务都在这。/run/systemd/system/运行时生成的单元文件重启就没了。/etc/systemd/system/管理员自定义的单元文件优先级最高。这个设计非常好用。如果你要改一个服务的配置但不想动软件包原文件就往 /etc/systemd/system/ 里放一个同名文件甚至只放一个片段。运行 systemctl daemon-reload 后你的修改就会覆盖系统默认配置。RHEL 官方文档中把这个机制叫“单元文件覆盖”考试也考。用 systemctl cat 可以查看一个单元最终生效的完整配置它会自动把所有层的文件合并显示同时用注释标出每个文件来自哪里。这是排查“为什么配置改了没生效”的第一利器。4.2 服务单元关键字段扫盲一个典型的 sshd.service 包含这些重要字段[Unit] 段Description服务描述。After指定启动顺序不创建依赖关系。Requires硬依赖被依赖单元失败自己也失败。Wants软依赖被依赖单元失败不影响自己。Conflicts互斥关系不能同时运行。[Service] 段Type启动类型常见有 simple、forking、oneshot、notify。simple 表示主进程直接运行forking 表示主进程 fork 出子进程后就退出老派守护进程常用oneshot 表示执行完就退出的任务notify 表示进程启动完成后通过 sd_notify 通知 systemd。ExecStart启动命令。ExecStop停止命令。Restart失败后重启策略可取 no、on-failure、always、on-abnormal。User/Group以什么身份运行。[Install] 段WantedBy这个服务被哪个 target 拉入写 multi-user.target 就表示多用户模式下开机自启。Alias别名。从排障角度Type 和 Restart 是隐藏大坑。比如一个服务 Type 写的是 forking但实际上主进程不退出systemd 会认为启动失败报 timeout。反之Type 写 simple 但进程自己 fork 了systemd 又会以为服务已经准备好其实还没监听端口。这些经验在排障时非常管用。4.3 覆盖文件到底怎么写RHEL 系统里覆盖文件的推荐做法是建一个目录/etc/systemd/system/xxx.service.d/。比如要修改 httpd 服务的一些参数可以创建 /etc/systemd/system/httpd.service.d/custom.conf里面写[Service] Restarton-failure RestartSec5然后 systemctl daemon-reload systemctl restart httpd 生效。用 systemctl cat httpd 就能看到合并后的效果。这种做法比直接改 /usr/lib/systemd/system/httpd.service 安全得多软件包更新时不会覆盖你的定制内容系统升级也不会丢配置。这也是生产环境的标准做法考试里如果让你“修改服务配置但不碰原始文件”就是在考这套机制。写覆盖文件后忘了 daemon-reload 是绝大多数“配置改了不生效”的原因。systemd 加载单元信息是在启动时和 daemon-reload 时不是实时读取。所以我反复跟新同事强调改完 unit 文件第一件事是 daemon-reload然后再 restart顺序不能乱。5. 排障实战journalctl、systemd-analyze 和常见问题5.1 journald 日志比 syslog 更省心的存在systemd 自带的日志系统叫 journald它把内核日志、服务标准输出、服务错误输出集中管理。查看服务日志用 journalctl -u xxx.service查看启动日志用 journalctl -b。最常用的几个参数-u 指定单元。-f 实时跟踪类似 tail -f排障时好用到爆。-p err 只看 error 级别以上的日志。--since today --until 2025-01-01 12:00:00 按时间过滤。-n 50 只看最近 50 条。有个小技巧日志服务没启动时无法保存日志如果 systemd-journald 本身出问题你会发现 journalctl 什么都查不到。这时先看 /var/log/journal 目录是否为空再判断是磁盘问题还是服务没起来。日志默认是存储在内存里/run/log/journal重启就丢。要持久化创建 /var/log/journal 目录并设置好权限RHEL 官方推荐做法是mkdir -p /var/log/journal systemctl restart systemd-journald。生产环境我都是第一时间做持久化否则出了故障重启后日志全没了只能干瞪眼。5.2 分析开机慢命令的隐藏价值systemd-analyze 是分析启动性能的神器。直接用 systemd-analyze 会显示内核启动时间、initrd 时间和用户空间启动时间。想看每个单元耗时用 systemd-analyze blame它会把所有单元按启动耗时降序排列。我会用它来找开机慢的元凶比如某个 network 服务卡了 30 秒一查就知道。还有一个很实用的子命令systemd-analyze critical-chain xxx.target。它会输出指定 target 的依赖链标出每个环节的耗时。定位“哪一步卡住系统”最有用。比如开机卡在 network-online.target就能顺着链子往下看是哪个服务引发的问题。考试对 systemd-analyze 的要求不高但实际操作中价值很大。面试时候随口说出“我用 systemd-analyze blame 查出过某个服务拖慢开机”比死记二十个命令更有说服力。5.3 服务起不来的三招排查法我总结了一个服务排障“三步走”第一步systemctl status xxx.service看状态是 failed 还是 activating看有没有报错行。很多时候错误信息直接在这里比如端口被占用、配置文件语法错。第二步journalctl -u xxx.service -n 50看完整日志。status 只显示最近几条不一定够日志里经常有更详细的描述。第三步systemctl show xxx.service -p ExecStart -p Type -p User确认进程实际是怎么被启动的字段有没有和预期不符。这套方法基本能解决 80% 的服务启动问题。剩下 20%往往是 SELinux 在捣乱。RHEL 上服务起不来如果日志里出现 avc: denied 字样用 ausearch -m avc -ts recent 查详情再用 semanage 调整策略。千万别关 SELinux 来图省事那是把安全当儿戏生产环境绝对不可取。5.4 常见问题速查表症状可能原因排查方向start 后 2 秒内又挂ExecStart 命令路径错误或权限不足journalctl 日志、systemctl showenable 提示找不到单元单元名拼错或未 daemon-reloadsystemctl list-unit-files改了配置不生效忘 daemon-reload先 reload 再排查服务一直在 activatingType 声明与实际进程行为不符检查 Type、ExecStart 行为服务 kill 不掉主进程没退出子进程还在systemctl kill --kill-whoall开机卡在某个点某个 target 依赖的服务超时systemd-analyze critical-chain日志不持久/var/log/journal 目录不存在创建目录后重载 journaldSocket 文件残留服务异常退出没清理systemctl stop 后再清理6. 守护进程与会话从进程生命周期看服务6.1 会话概念守护进程为何要“离群索居”“守护进程与会话”是目前社区里讨论度不低的话题因为它直接关系到你对进程模型的理解。在 Linux 里每个进程都属于一个会话session会话由会话首进程session leader创建。一个会话可以包含多个进程组一个终端tty关联一个会话。传统守护进程有个典型特征它是一个会话首进程同时不再拥有控制终端。为什么因为守护进程是后台长期运行的如果它占着终端你敲个命令都得被它输出刷屏而且终端一关内核会向会话里的进程发送 SIGHUP守护进程不想被这个信号误伤就会选择脱离终端。经典实现手法是“双 fork setsid”。第一次 fork 后子进程调用 setsid创建新会话成为会话首进程第二次 fork 再让进程放弃“会话首进程”身份避免以后重新获取控制终端。这套操作在老派 C 程序里非常常见daemon() 函数干的就是这个事。6.2 systemd 如何重新定义守护进程systemd 改变了守护进程的传统玩法。以前进程要自己实现 double-fork 来脱离终端现在 systemd 直接用能力capabilities来操作。你用 systemctl start 时systemd 会把你启动的进程放进一个私有 cgroup直接接管它的生命周期不再依赖终端会话概念。所以现代服务文件里 Typesimple 的进程根本不需要自己 fork 脱离终端systemd 已经替它把“后台化”做了。考试里常问的一个点是“如何把一个服务改成不 fork 的 Type”或者“为什么 systemd 服务进程 PID 和 pgrep 查出来不一样”答案都在 cgroup 概念里。用 systemctl status 显示的 PID 是主进程其他子进程可以通过 systemctl status 输出的 CGroup 列表查看。实际上systemd 就是把整个 CGroup 当做一个服务单元来管理而不是只盯一个 PID。6.3 会话和 job 的关系容易踩的坑再深入一点systemd 本身也有“job”概念用来表示一项待执行的请求比如 start 或 stop。它和用户登录会话session是两回事但初学者老混。用户会话指的是你用 SSH 登录后产生的登录会话有 ttysystemd 的 job 则是一个内部队列任务。你执行 systemctl stop会先生成一个 stop job由 systemd 排期执行。排障中遇到“Transaction for xxx.service failed”或“Job for xxx.service failed because a timeout was exceeded”就是在说 job 执行失败。前者多半是依赖冲突比如两个服务互斥后者多半是启动超时默认 90 秒没起来就放弃。还有个小坑用 CtrlC 取消 systemctl start 命令只取消等待不代表服务不启动了。job 提交给 systemd 后你前台中断的只是等待过程。这个细节看似小生产环境如果有人“取消”了重启操作结果服务还是重启了容易闹乌龙原理就在这里。6.4 守护进程设计给运维的启示理解守护进程与会话对日常运维有三个实际帮助第一解释“为什么 nohup 和 不一定管用”。nohup 是忽略 HUP 信号但如果会话关闭时终端发的是别的事件还是有风险。现在规范的做法是用 systemd-run 来创建瞬时服务把任意命令放进 systemd 管理享受日志、依赖、重启策略全套服务。第二理解 SSH 会话关闭后服务会不会死。如果服务是通过 systemctl 启动的它已经脱离你的会话关终端无影响。如果是你在 shell 里手工跑的一个进程关终端它就收到 HUP多半会退。所以工作流上常驻进程一律交给 systemd 管理。第三理解容器和 systemd 的关系。现在很多 Linux 容器跑的是 systemd 作为 init它实际上就是在容器里管理多个服务和裸金属上的逻辑一模一样。掌握了 systemd再看容器里 pid 1 跑 systemd 的架构就会有一种“原来如此”的通透感。用 systemd-run 跑一次性任务的例子systemd-run --unitmy-task --scope --slicebackground.slice sleep 300这个命令会创建一个 scope 单元跑 sleep 300然后你可以用 journalctl -u my-task 看它的输出。临时想跑个东西又不想污染服务列表这个命令很实用。7. 我的备考与实战经验最后分享一点个人体会。RH124 这一章的内容考试只是起点真正价值在于帮你建立正确的操作心智。我见过太多人在生产环境里出问题根源就是 enable 和 start 不分、target 和 service 混淆、改完配置不重载。这些细节考过一次后会记住一阵子跑过一次生产故障后会记住一辈子。给你几个具体建议。第一平时练习别怕玩坏开个虚拟机把服务反复 enable、disable、mask、unmask亲手体会各种状态之间的转换。第二多读状态输出systemctl status 里的每一行都有含义别只盯着 active (running)。第三遇到服务起不来先看日志再想方案别一上来就重启大法——日志会告诉你真相重启只会暂时掩盖问题。把这一章吃透后面学网络配置、存储管理、系统安全都会顺畅很多因为所有服务相关操作都建立在 systemd 的根基上。这套知识用到生产上可以帮你少熬夜、少背锅、多拿绩效比死记硬背命令划算得多。