服务挂了。
service nginx status 傻傻地在那儿显示 running,但网页死活打不开,curl 直接超时。进程明明还在,它就是不响应。
要是用 systemd,第一反应就是敲一句:
journalctl -u nginx -n 50 --no-pager
屏幕上直接吐出带时间戳的最近 50 行日志:哪个进程因为吃内存太多被系统一枪崩了,哪个端口没监听起来,写得清清楚楚。半分钟内就能定位。
而在以前,你得先去 /var/log/nginx/error.log 摸索,没收获再去 /var/log/syslog 碰运气,甚至得翻 dmesg。最痛苦的是这些地方的时间格式还不一样,你得在脑子里人肉拼时间线,还要保佑昨天刚跑的日志轮转没把关键报错给切走。
这只是日常运维里最不起眼的一处改动。但每次网上吵 systemd 该不该存在,大家都喜欢在半空中扯哲学架构,懒得看一眼这些天天碰到的脏活累活。
反对的人最常挂在嘴边的一句是:systemd 违反了 Unix 哲学,PID 1 作为系统天字第一号进程,应该越精简越好,塞那么多功能进去,万一崩了整台机器不就当场瘫死?
逻辑听上去没毛病,可惜前提不对:日志、网络、设备管理这些重活,压根就不在 PID 1 里跑。
很多人总觉得 systemd 是一个塞满垃圾、动辄几十兆的巨型单体进程。但你只要在任何一台机器上敲个 ps aux | grep systemd 验证一下,就能看到一堆各司其职的独立进程。
/lib/systemd/systemd 作为 PID 1,管的是服务调度这条主线——读服务的配置文件、算清楚谁依赖谁、把服务拉起来又停下去、盯着磁盘挂载和进程分组(cgroup)。它不算轻,但那些最容易出事的重活,它自己没碰。
真正的重活是拆出去的:收日志的是独立的 journald,管网络的是 networkd,处理热插拔设备的是 udevd。
它们各自有独立的 PID,之间靠 socket、D-Bus 这类机制通信。要是负责收日志的进程不小心崩了,PID 1 连眼皮都不眨一下,业务进程照样欢快地跑,顶多是这会儿日志写不进去了。管网络的进程死了,老连接也断不掉。这种设计跟单体没关系,反倒有点像跑在单机上的微服务。
你可以嫌它工具全家桶里塞的小工具太多,这是个值得掰扯的真问题;但非要揪着 PID 1 容易带崩整台机器不放,那真是在打空气墙了。
在 SysVinit 时代,服务启动的依赖管理就是一门玄学。服务先起后起全靠文件名开头的数字排辈分,比如 S20mysql、S80nginx。你想让 nginx 在 mysql 准备好了之后再启动?除了在 nginx 启动脚本里手写一句 sleep 2 之外,基本只能看天意。要是哪天数据库起得慢了,nginx 报错起不来,你只能干瞪眼。
服务进程崩了?要是脚本作者没写死循环守着,死了就真的死了,根本没人去拉它。跑个 status 命令给你返回 OK,其实可能只是脚本在里头简单 echo 了一句 running,底下的真进程早就成了僵尸。
真不是偏心 systemd,而是当年那些起步脚本留下的坑太大。不管你喜不喜欢它,它起码把下面这几件事定成了行业规矩:
一是把依赖关系摆在明面上。 谁等谁、谁跟谁没关系,直接写进配置(After、Requires 这些),系统自己排顺序并发拉起,不用再猜。服务器开机也因为这,从几分钟缩到了几秒。
二是 cgroup 强绑定。 每个服务和它生出来的所有子进程,统一放进一个 cgroup 组里。叫它停,它就得连子子孙孙一起交资源,后台再也不会留下偷偷占着端口的孤儿进程。
三是服务死了能自动救活。 以前为了防进程挂掉,还得另外装个监控工具,或者写个脚本定时去探活。现在写行配置(Restart=on-failure),挂了自动重试,少熬好多个夜。
到今天,绝大多数业务都搬进了容器。在这个场景下,systemd 确实有点尴尬。
容器最讲究单进程,也就是一个容器只干一件事。容器里服务的生命周期、健康检查、宕机重启,全被 Kubernetes 或者 Docker 的守护进程包揽了。在容器里硬跑 systemd,不仅要给特权,还得把 cgroup 挂载进去,纯属多此一举。
所以对写业务代码的开发来说,systemd 基本成了透明人,在容器里感觉不到这玩意的存在。
可对管基础设施的运维、SRE 来说,这地盘还是雷打不动。kubelet、containerd 这些底层引擎在虚拟机和宿主机上跑,依然得靠 systemd 来管理。
这直接把写业务的开发和管底层基建的运维切成了两拨人。开发在容器里不用碰 systemd,运维还在宿主机上天天看 journalctl,两边基本说不到一块去。
服务器上真香,硬塞进容器就是找骂。
说到底,需不需要,得看你拿这台机器干嘛。
跑服务器或者个人桌面,直接用。 要管的服务多、要进程死了自动重启、要查日志,它解决的都是刚需。不用它,自己去用脚本拼替代品,纯属折腾自己。
单进程容器和嵌入式设备,根本用不着。 容器里就跑一个主程序,找个几十 KB 的 tini 转发下信号就够了,塞个 systemd 反而要开特权、挂资源。路由器、摄像头这种内存紧巴巴的设备,busybox init 或者 OpenRC 才是正解。
服务器要的是一整套现成的系统管理方案,而不是极简;容器要的是个信号转发工具。两边需求不一样,本来就不该往一块凑。