☰
进程、资源观察与 Systemd 服务管理
2026/10/11 7:45:47 网站建设 项目流程

一、程序、进程、线程:一句话分清

  1. 程序是磁盘上的可执行文件,比如 /usr/sbin/nginx,它安安静静躺在硬盘上,还没有运行,关键标识是文件路径。
  1. 进程是程序的一次运行实例。程序一旦被启动,操作系统就给它一份独立的内存、文件描述符和运行身份,并发给一个编号,这个编号就是 PID。
  1. 线程是进程内部的执行单元。一个进程内部可以开很多线程,它们共享进程的内存和资源,每个线程有自己的编号 TID,也叫 LWP。

同一个程序可以同时运行成多个进程。Nginx 就是这样:磁盘上只有一份 /usr/sbin/nginx,启动后却形成一个 master process 和多个 worker process,它们是不同的进程,各有各的 PID。千万不要把 worker 误认为线程;而 Jenkins 那种 Java 程序反过来,通常只有一个 Java 主进程,内部跑着很多线程。

二、PID、PPID 与进程树

PID 是进程编号,系统里每个进程都有,且同一时刻不重复。PPID 是父进程编号,记录这个进程是由谁启动的。

Linux 里所有进程的祖先都是 systemd,它的 PID 固定是 1。Nginx 由 systemd 拉起,master 的 PPID 指向 1;worker 由 master 拉起,worker 的 PPID 指向 master。顺着 PPID 一路往上追,就能画出一棵进程树。排查问题时,这棵树能告诉你一个进程到底是谁启动的、归谁管。

三、进程状态:R、S、D、T、Z

40 个玩家是 40 个进程,2 个服务器核心是 2 个 CPU 核心。
正在游戏里的,是 Running;匹配成功、排队进图的,是 Runnable。这两类在ps里都显示为 R。
等硬盘加载地图的,是 D 状态,等待不可中断 I/O,不响应普通信号,kill也杀不掉。
等队友上线的,是 S 状态,可中断睡眠,队友一上线就唤醒。
还有 T 和 Z:被裁判暂停的,是 T;角色已退出但队伍仍占位、队长没确认的,是 Z,僵尸,子进程结束但父进程没读取退出状态。

核心映射都一样:Running/Runnable → R;可中断睡眠 → S;不可中断 I/O → D;暂停 → T;僵尸 → Z。

四、观察进程的几类工具

  1. ps 是拍照:拍一张当前所有进程的快照。ps aux 看用户、CPU、内存和完整命令行;ps -ef 看 PID、PPID 和父子关系;ps -eo 可以自己挑字段。
  1. pgrep 和 pidof 是查号台:直接按名字返回 PID,省去自己 grep。pgrep -o 取最早启动的那个,Nginx 场景下通常就是 master。
  1. pstree 是画家:把进程树画出来,-p 带 PID,-s 沿父进程向上追。
  1. top 和 pidstat 是录像:连续刷新观察。ps 只拍一张,异常往往是趋势,要看连续画面才能下结论。
  1. ss 是查端口登记簿:ss -lntp 能从端口号反查出是哪个进程在监听,顺着端口找到 PID,再找到程序和 Unit。

五、信号:礼貌敲门与强行破门

信号是请求或强迫进程做动作的方式。Day 09 重点讲三个:

  1. TERM(15 号):礼貌敲门,请求进程正常退出。进程有机会保存数据、关闭文件、通知伙伴。优先使用。
  1. HUP(1 号):具体行为由程序定义,很多服务把它当作重新加载配置的指令。用之前先查文档。
  1. KILL(9 号):强行破门。它由内核直接执行,进程根本没有机会清理现场,可能留下锁文件、丢数据。是最后手段。

正确顺序永远是:先确认 PID,再发 TERM,等一等、验证一下;实在退不出去才用 KILL。管理 Systemd 服务时更优先用 systemctl stop 或 reload,让超时和子进程都由 Systemd 统一处理。

六、前台、后台与 nohup

  1. 前台运行:命令占着当前终端,终端不能干别的。
  1. 命令后面加 &:直接放到后台跑,终端腾出来了,$! 保存它的 PID。
  1. Ctrl+Z:把前台正在跑的命令暂停,变成 Stopped 状态。
  1. bg %1:让 1 号作业在后台继续跑;fg %1 把它带回前台;jobs -l 随时看作业列表。注意 %1 是作业编号,只在当前 Shell 有效,不是 PID。
  1. nohup:让命令在终端关闭后继续运行,输出写进文件。适合临时任务;长期服务应该交给 Systemd,因为 Systemd 还提供开机自启、失败恢复、统一日志和运行身份管理。

七、Load Average:系统的排队长度

uptime 显示最近 1、5、15 分钟的 Load Average,可以理解为任务排队长度。判断时要除以 CPU 核心数:nproc 告诉你有几个核心。

以 4 核、负载 8.00、4.00、2.00 为例:1 分钟值除以 4 是 2.0,每个核心平均排 2 个任务,压力较高;5 分钟值是 1.0,接近满载;15 分钟值是 0.5,有余量。三个值从过去到现在是 0.5、1.0、2.0,说明压力正在爬升。

两个关键认知:

  1. 每核心负载小于 1 通常有余量,接近 1 是满载,大于 1 说明有任务在排队,或 D 状态任务多。
  1. Load Average 统计了 D 状态任务,所以它不等同于 CPU 使用率。磁盘卡住也会抬高负载。第一轮用它快速判断,最终要结合 top、vmstat 和业务表现确认。

八、内存:available 才是真话

free -h 里最容易看错的是这一条:内存看起来很忙,不等于内存不够。

Linux 会把暂时空闲的内存拿去做缓存:cache 保存近期读过的文件数据,下次读同一个文件就不用碰磁盘;buffer 暂存并整理准备写入磁盘的数据。这些缓存随时可以回收,回收后给应用程序用。所以看内存要优先看 available 这一列,它才是真正可用的量;buff/cache 很高不是坏事。

Swap 是拿磁盘当内存的应急通道。si、so 这些换入换出动作说明物理内存真的紧张了。Swap 只能临时缓解,不能代替物理内存。

九、vmstat 与 /proc

  1. vmstat 1 5 每 1 秒采样一次共 5 次。r 是等 CPU 的任务数,si 和 so 是 Swap 换入换出,us、sy、id 是用户态、内核态、空闲 CPU 占比,wa 是等 I/O 浪费的 CPU 时间。第一行是开机以来的平均值,判断趋势要看后面的行。
  1. /proc 是内核提供的运行状态入口,不是普通目录。/proc/PID/status 看进程状态、内存、线程数,/proc/PID/cmdline 看启动参数,/proc/PID/fd 看打开的文件。PID 消失,对应目录也跟着消失。
  1. /sys 是设备与内核属性视图,比如 /sys/class/net 看网卡、/sys/class/block 看块设备。本阶段只读不改,错误修改可能影响系统运行。

十、Systemd 与 Unit:服务的总管家

Systemd 是 Ubuntu 的系统与服务管理器,PID 为 1,开机后第一个启动。所有长期服务的启动、停止、重启、开机自启、崩溃后拉起,都归它管。

Unit 是一份声明式的说明文件,告诉 Systemd:这个服务怎么启动、以谁的身份跑、挂了要不要重启、要不要开机自启。常见类型:.service 长期服务、.socket 套接字监听、.timer 定时触发、.target 组合目标、.mount 挂载点。systemctl 是操作这些 Unit 的统一入口。

三个容易混淆的命令:

  1. daemon-reload:改了 Unit 文件本身,让 Systemd 重新读一遍定义。它不会重启任何服务。
  1. reload:服务的配置文件改了,让服务进程自己重新加载配置,进程不换、PID 不变,前提是程序支持这个动作。
  1. restart:整个进程停掉再拉起,PID 通常改变。

十一、四层检查:判断服务真的活着

一个服务显示 active,只说明 Systemd 认为它起来了。完整的健康确认要过四层:

  1. Unit 层:systemctl is-active 或 status,确认服务状态正常。
  1. 进程层:pgrep 或 ps,确认进程真的存在、身份对。
  1. 端口层:ss -lntp,确认该监听的端口在监听。
  1. 应用层:curl 一个真实 URL,确认程序能返回正确响应。

这个顺序从里到外,一层层排除。后面排查故障也按这个顺序复测。

十二、Nginx 多进程与 Jenkins 多线程

两种服务模型对比:

  1. Nginx:一个 master 加多个 worker,多个 PID,监听 80 端口,软件包安装时自带 Unit。观察重点是多个进程各自的 CPU、内存。
  1. Jenkins WAR:一个 Java 主进程,内部很多线程,一个 PID 多个 TID,监听 8080 端口,Unit 需要自己写。观察重点是用 ps -L 或 top -H 深入到线程层面。

不管哪种模型,最后都交给 Systemd 管理,这是本课的主线:先看懂进程,再学会控制进程,最后把程序交给 Systemd。

十三、Service Unit 的四个核心问题

写一个最小可用的 Service Unit,先回答四个问题:

  1. 按什么顺序启动:After=network.target 表示网络就绪后再启动。
  1. 以谁的身份运行:User 和 Group 指定专用账号,不用 root。
  1. 执行哪个程序:ExecStart 写清楚启动命令和参数。
  1. 失败后怎样处理:Restart=on-failure 表示异常退出时自动拉起,RestartSec=5 表示等 5 秒再拉。

先写最小可用 Unit,再按需要补充资源限制等内容。另外 SuccessExitStatus=143 的作用是:143 等于 128 加 15,是进程收到 TERM 信号的退出码,把它声明为正常退出,可以避免正常 stop 被当成失败而触发重启。

十四、nice 值:CPU 调度的谦让度

Nice 值范围 -20 到 19:数值越小越优先,越大越谦让。普通用户可以调低自己进程的优先级(变得更好说话),但调高优先级需要管理员权限。要注意 Nice 只影响 CPU 调度的倾向,不保证执行先后,也不限制用量,不能拿来解决磁盘、网络或锁等待问题。

十五、僵尸进程为什么杀不掉

僵尸进程本身已经结束了,只剩一条退出状态记录等父进程来读。它不占 CPU 也几乎不占内存,但对它发 kill -9 没有任何用,因为它已经死了。正确的思路是去调查它的父进程为什么迟迟不回收,必要时让父进程处理问题或重启父进程。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询