13424 字
67 分钟
Linux基础(7):Linux进程管理体系详解

前言#

[!NOTE] 核心引言 进程是Linux系统资源分配的基本单位,所有系统服务、应用程序和用户操作最终都以进程的形式运行。对于运维人员而言,熟练掌握进程管理是排查系统负载过高、资源泄漏、服务异常等问题的核心技能。本文将系统讲解进程分类、异常进程原理与解决方案、核心查看命令及控制机制,并深入探讨后台进程运行、网络连接查询等高阶主题,适用于所有主流Linux发行版。

一、进程基础与分类#

1.1 进程基本概念#

进程是程序的一次动态执行过程,拥有独立的内存空间、文件描述符和系统资源。每个进程都有唯一的标识:

  • PID (Process ID):进程ID,全局唯一
  • PPID (Parent Process ID):父进程ID
  • UID/GID:进程所属的用户ID和组ID

Linux系统启动时,第一个运行的进程是 systemd(PID=1),它是所有进程的祖先,负责管理系统服务和回收孤儿进程。

1.2 进程常规分类#

进程类型特点示例
前台进程运行在终端,占用终端输入输出,用户可直接交互执行 ls、vim 等命令
后台进程运行在后台,不占用终端,用户无法直接交互命令末尾加 & 执行:sleep 300 &
守护进程 (Daemon)特殊的后台进程,随系统启动,持续运行提供服务sshd、nginx、crond
内核进程由内核创建,运行在内核态,管理系统资源名称以 [ 开头,如 [kworker]、[kswapd]

1.3 异常进程详解#

[!IMPORTANT] 系统排查关键点 异常进程是导致系统不稳定的常见原因,掌握其特征与处理机制至关重要。

1.3.1 孤儿进程#

  • 定义:父进程先于子进程退出,子进程失去父进程,成为孤儿进程。
  • 处理机制:系统会自动将其收养给 systemd(PID=1),并在子进程退出时自动回收资源。
  • 危害:无任何危害,属于正常的系统托管行为,无需人工干预。

1.3.2 僵尸进程#

  • 定义:子进程先于父进程退出,但父进程没有调用 wait() 或 waitpid() 回收资源,子进程的进程控制块 (PCB) 仍然残留在系统中。
  • 核心特点:
    • 已经释放了内存、CPU等大部分系统资源,只保留 PCB。
    • 持续占用系统 PID 资源池(系统可用 PID 默认约束为 32768)。
    • 大量堆积会导致系统无法创建任何新进程。

[!TIP] 僵尸进程终结指南 请按以下优先级顺序尝试解决僵尸进程问题:

zombie_killer.sh
# 1. 优雅通知父进程回收子进程
kill -17 <父进程PID>
# 2. 如果父进程无响应,则尝试正常终止父进程(终止后僵尸进程转为孤儿,由systemd统一回收)
kill -15 <父进程PID>
# 3. 最后通牒:强制干掉父进程!
kill -9 <父进程PID>
# 极端情况:如果上述方法全部失效,才考虑重启系统。

二、进程查看核心命令#

2.1 ps 命令:静态查看进程#

[!NOTE] 核心技能 ps 用于获取当前时刻的系统进程快照,是日常诊断最基础的利器。

2.1.1 基础语法与参数讲解表#

参数全称用途说明常见组合示例命令
aall users显示所有用户的所有进程必须与 x 组合ps aux、ps ax
uuser format采用用户友好的信息输出格式与 ps a 组合ps aux
xwithout tty显示没有终端的进程(后台进程)与 ps a 组合ps aux
-eevery process显示系统内的每一个进程System V风格ps -ef、ps -aux
-ffull format提供完整的进程信息及父子关系与 -e 组合ps -ef
-ooutput format自定义输出字段(极度灵活)精细化查询ps -o pid,ppid,cmd
-Ccommand仅显示指定程序名称的进程快速定位ps -C nginx
-ppid仅显示指定PID的进程信息精准查询ps -p 1234,5678
-Uuser仅显示指定用户的所有进程权限审计ps -U root
--forest / --treehierarchy以树形结构显示进程层级关系依赖分析ps --forest -ef
-Hshow process tree树形输出父子进程关系父子链追踪ps -eH
Lthread显示进程的线程信息多线程诊断ps -eLf
-wwide output禁止输出行宽限制,显示完整命令行长命令查看ps auxww

最常用组合速记:

Terminal window
ps aux # BSD风格,最常用的全能查询命令(务必死记硬背!)
ps -ef # System V风格,显示完整进程树及父子关系
ps -eH # 树形显示所有进程的调用关系链路
ps -C nginx # 快速查询特定程序
ps -o pid,ppid,cmd --sort=-%cpu # 自定义格式并按CPU使用率倒序

2.1.2 ps aux 输出字段深度解析(模拟输出示例)#

实际执行命令 ps aux 的真实输出:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 24068 3816 ? Ss Jan08 0:02 /lib/systemd/systemd --system --deserialize
root 45 0.0 0.1 17320 2960 ? Ss Jan08 0:00 /lib/systemd/systemd-journald
root 123 0.0 0.0 99920 2456 ? Ss Jan08 0:01 /lib/systemd/systemd-udevd
message+ 234 0.0 0.1 7352 2120 ? Ss Jan08 0:00 /usr/bin/dbus-daemon --system --address=
root 456 0.1 0.2 105400 5892 ? Ss Jan08 0:15 /usr/sbin/sshd -D
postgres 890 0.0 1.2 215640 48920 ? Ss Jan08 0:32 /usr/lib/postgresql/14/bin/postgres
xiaoying 1024 0.5 0.8 1542880 32456 ? Sl 10:30 1:23 /usr/bin/python3 /home/xiaoying/app.py
root 2048 0.0 0.0 21544 1204 pts/0 Ss 10:35 0:00 -bash
xiaoying 2234 2.1 3.5 2048000 139876 pts/0 Rl+ 10:36 0:08 java -Xmx512m -jar myapp.jar
xiaoying 2345 0.0 0.0 9932 640 pts/0 S+ 10:37 0:00 grep nginx
root 3456 0.0 0.0 0 0 ? S Jan08 0:00 [kworker/0:0-kblockd]
root 3789 Z 0.0 0 0 ? Z Jan08 0:00 [defunct]
字段名示例值含义详解
USERroot、xiaoying进程所属的用户名(哪个账号启动了这个进程)
PID1、2234进程的全局专属唯一标志号 ID(系统内绝不重复)
%CPU0.0、2.1进程正在霸占整个物理 CPU 算力的百分比(多核CPU时为平均占用)
%MEM0.1、3.5进程正在消耗整个物理内存的百分比(与系统总内存相比)
VSZ168684、2048000虚拟内存申请量 (KB):含真实物理内存+交换分区+运行依赖的共享库额度(理论可申请但未必使用)
RSS13284、139876常驻物理内存占用 (KB):实打实扣减的物理内存(不含 Swap 区与共享库,这是真正在用的内存)
TTY?、pts/0进程所绑定的终端器设备,显示 ? 代表为脱离终端控制的后台守护类进程;pts/0 代表伪终端0
STATSs、Rl+、Z进程当前生存状态特征码(详见下方状态字典表解析)
STARTMay10、10:30进程启动时的具体日历时间或时刻
TIME0:03、1:23进程自出生以来累计占用消耗掉的 CPU 计算时长总和
COMMAND/usr/lib...、/usr/bin/python3 /home/xiaoying/app.py调起该进程的完整原生命令行执行路径与携带参数

2.1.3 STAT 状态码字典补充#

stat_codes.txt
R : (Running) 运行状态,正在 CPU 上执行或处于队列中等待被调度
S : (Sleeping) 可中断睡眠,等待特定事件触发,可随时被信号唤醒
D : (Disk Sleep) 不可中断睡眠,绝大多数处于深度磁盘 IO 阻塞,无法被常规信号唤醒
Z : (Zombie) 僵尸态,程序已实质性终结但骨灰尚未被收容
T : (Stopped) 停止态,通常因人为信号暂停或正挂在调试器(GDB)上运行
修饰符号(可跟在主状态后):
s : session leader 会话首发进程(控制一个会话的主控权)
l : multi-thread 代码处于多线程状态(含多个执行线程)
+ : foreground 隶属于前台进程组(当前在终端上活跃交互)
- : background 后台进程,不在前台进程组中
< : high priority 高优先级进程(通过 nice 值提权)
N : low priority 低优先级进程(通过 nice 值降权)

2.1.4 pstree 命令:进程树形结构展示#

pstree 以树形结构清晰展示进程的父子关系,比 ps --forest 更加直观美观。

参数讲解表:

参数全称用途说明示例命令
-pshow pids同时显示每个进程的PID号pstree -p
-ushow uid显示进程所属的用户名变化pstree -u
-ashow args显示每个进程的完整命令行参数pstree -a
-llong lines不限制输出行宽,完整显示长命令pstree -l
-hhighlight高亮显示当前进程及其祖先pstree -h
-s <pid>show subtree只显示指定进程的子树pstree -s 1234
-AASCII使用ASCII字符绘制树形结构pstree -A

模拟输出示例:

Terminal window
# 执行: pstree -p
systemd(1)─┬─systemd-journald(45)
├─systemd-udevd(123)
├─sshd(456)─┬─sshd(2048)───bash(2050)───vim(2051)
│ └─sshd(3000)───bash(3002)
├─postgres(890)─┬─postgres(891)
│ ├─postgres(892)
│ └─postgres(893)
├─nginx(1200)─┬─nginx(1201)
│ └─nginx(1202)
└─...
# 执行: pstree -pu xiaoying
systemd(1)─┬─...
├─gnome-shell(2100,xiaoying)─┬─evolution(2101,xiaoying)
│ └─nautilus(2102,xiaoying)
├─java(2234,xiaoying)─┬─{java}(2235,xiaoying)
│ ├─{java}(2236,xiaoying)
│ └─...
└─...

实战应用:

Terminal window
pstree -p -u # 显示PID和用户信息的进程树
pstree -p bash # 仅显示bash进程及其子树
pstree -s 2234 # 显示PID 2234这个进程的完整祖先链路
pstree -a -p java # 显示java进程树并附带完整命令行参数

2.2 top 命令:实时监视系统脉搏#

[!NOTE] 核心技能 top 是 Linux 性能瓶颈分析的万金油工具。命令行输入 top 并回车后,系统整体运行大盘面板将实时动态展现。

参数讲解表:

参数全称用途说明示例命令
-bbatch mode非交互式模式,直接输出然后退出(适合脚本调用)top -b -n 1
-n <num>number of iterations执行指定次数的刷新后自动退出top -b -n 3
-d <sec>delay设置刷新周期(默认3秒)top -d 1
-p <pid>monitor pids仅监视指定PID的进程top -p 1234,5678
-u <user>user filter仅显示指定用户的进程top -u xiaoying
-iidle processes不显示闲置进程top -i
-1single cpu分别显示每个CPU核心的负载(不汇总)top -1
-s <col>sort by column按指定列排序(需指定列号)top -s %CPU
-Hthreads显示线程级别的信息而非进程级别top -H

2.2.1 top 交互模式详解#

执行 top 命令后的实时输出示例:

top - 10:30:45 up 2 days, 4:50, 2 users, load average: 0.15, 0.08, 0.05
Tasks: 120 total, 1 running, 119 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.2 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 7859.2 total, 4521.3 free, 1234.5 used, 2103.4 buff/cache
MiB Swap: 8192.0 total, 8192.0 free, 0.0 used. 6234.1 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2234 xiaoying 20 0 2048000 139876 45678 R 2.1 3.5 1:23.45 java -Xmx512m
1024 xiaoying 20 0 1542880 32456 12345 S 0.5 0.8 1:23.12 python3 /home/xiaoying/app.py
890 postgres 20 0 215640 48920 32100 S 0.0 1.2 0:32.56 /usr/lib/postgresql/14/bin/postgres
456 root 20 0 105400 5892 3456 S 0.1 0.2 0:15.23 /usr/sbin/sshd -D
123 root 20 0 99920 2456 1234 S 0.0 0.0 0:01.45 /lib/systemd/systemd-udevd
1 root 20 0 24068 3816 2345 S 0.0 0.1 0:02.34 /lib/systemd/systemd --system
234 message+ 20 0 7352 2120 1234 S 0.0 0.1 0:00.56 /usr/bin/dbus-daemon --system
3456 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 [kworker/0:0-kblockd]

2.2.2 第 1 行:系统运转概况与生存压力指标#

指标字段样例输出极限值与运维含义剖析
Top Statustop - 10:30:45主机操作系统现在的标准时间戳。
Up Timeup 2 days, 4:50系统自从上次开机后已连续安全运行的具体时长。
Users2 users当前正在有几个终端用户挂接到这台服务器。
Load average0.15, 0.08, 0.05最核心的排队负载数字!分别代表系统过去 1分钟、5分钟、15分钟 内的平均负载队列。警戒法则:一旦此数值长期超过系统物理 CPU 核心总数,意味着系统陷入严重拥堵卡顿!单核CPU警戒线为1.0,8核CPU警戒线为8.0。

2.2.3 第 2 行:全量进程生死账本统计#

状态类别样例数字运维含义剖析
Tasks120 total系统目前注册在案的所有进程总计数量。
running1正在使用物理 CPU 处理业务或者排在执行栈首位随时发动的进程数。
sleeping119陷入沉睡状态等待各种网络数据返回或定时器唤醒的进程数。
stopped0被断点调试卡住或被暂停信号定身的挂起级进程数。
zombie0高危重点观测区!已经死亡但未经父进程回收的僵尸进程堆积量,如该数值长期不为 0 则必须干预。

2.2.4 第 3 行:CPU 核心算力压榨拆解 (%Cpu)#

参数样例缩写全称性能瓶颈判断依据
us0.3User Space用户态占用:普通应用程序(如 Tomcat / Nginx 等)吃掉的算力百分比。正常应在10%-70%之间。
sy0.2System Space系统态占用:内核底层的调度算法及驱动层消耗掉的算力。若持续超过20%需排查内核 BUG 或驱动问题。
ni0.0Nice提权损耗:被通过 renice 修改过调度优先权的人工调整型进程消耗占比。
id99.5Idle Space大盘闲置率:CPU 剩余尚未分配出去的空暇能力。越高代表系统越宽松。若id<30%代表CPU处于高负载。
wa0.0Wait I/O磁盘阻塞灾难预警:等待底层硬盘存储设备读写反馈的干耗时间。致命红线:若长时间处于并超过 15%~20%,代表你的磁盘 IO 性能已经被彻底打穿!此时应立即排查磁盘读写瓶颈。
hi0.0Hard IRQ硬件中断占用:外部硬件设备(如网卡、磁盘)发起的中断抢占占比。若超过5%代表有频繁的硬件中断。
si0.0Soft IRQ软中断占用:系统内生软级别中断(如网络数据包处理)的占比。若持续超过10%代表网络处理繁重。
st0.0Steal Time虚拟机被宿主掠夺率:在虚拟机环境中,被宿主CPU强制抢占的时间占比。物理机此值为0。

2.2.5 第 4 & 5 行:内存水池与交换分区 (Mem & Swap)#

存储类型Total 总池Free 净空Used 实耗动态缓冲域 / 预估备转资金池
MiB Mem
(内存条物理总量)
7859.24521.31234.52103.4 (buff/cache)
用于加速文件读写的缓冲内存,这部分是活钱,当系统告急时内核会自动吐出来救火。实际可用内存 = Free + buff/cache。
MiB Swap
(硬盘低速顶替量)
8192.08192.00.06234.1 (avail Mem)
这是真正评估系统”还能容纳启动多少新进程”的可动用活水总容量指标。若avail Mem 接近0则系统面临内存枯竭风险。

2.2.6 top 高效交互快捷键与参数#

按键功能执行逻辑
P / M / T快捷将进程列表分别强制按照 CPU降序 / 内存降序 / 运行时长降序 重新排列整理。
1当面对 8 核 16 核等多 CPU 阵列时,打散汇总数据,独立展开每一个核心的实时负载柱状图。
c将默认被截断的进程短名,全景展开显示出具体的完整带参命令行启动路径。
k眼见为实:不退出观测界面的情况下,直接输入目标进程 PID 执行就地格杀指令。
f进入字段选择模式,可自定义选择要显示哪些列信息。
i切换是否显示闲置进程,可让输出更加洁净。
u按用户名过滤显示进程(输入用户名后按Enter)。
o自定义排序字段,非常灵活的排序选项。
W将当前的配置保存到 ~/.toprc 文件,下次启动时保持配置。
q退出 top 程序。
h显示帮助信息。

2.3 htop 命令:比 top 更强大的实时监控工具#

htop 是 top 的现代化增强版本,提供了更好的用户界面、更丰富的颜色高亮和更灵活的交互体验。

参数讲解表:

参数全称用途说明示例命令
-Cno-color禁用彩色输出htop -C
-d <delay>delay设置刷新间隔(以1/10秒为单位)htop -d 30
-u <user>user仅显示指定用户的进程htop -u xiaoying
-p <pid>pid仅监视指定PIDhtop -p 1234
-ttree以树形结构显示进程关系htop -t
-s <col>sort-key按指定列排序htop -s PERCENT_CPU
-Hhide-threads隐藏线程信息,仅显示进程htop -H
--pid=<pid>monitor-pid监控指定进程及其子进程htop --pid=1234
--filter=<str>filter按命令名过滤进程htop --filter=nginx

模拟输出示例:

[红色CPU柱状图] ████████░░░ 58.2% CPU
[黄色内存柱状图] ██████░░░░░░ 45.3% Mem
[绿色交换柱状图] ██░░░░░░░░░░░░░░░░░░ 2.1% Swp
PID USER PR NI VIRT RES SHR S CPU% MEM% TIME+ Command
2234 xiaoy 20 0 2048M 140M 45M R 45.8 3.5 1:23:45 java -Xmx512m
1024 xiaoy 20 0 1542M 32M 12M S 5.2 0.8 1:23:12 python3 app.py
890 post 20 0 210M 47M 31M S 0.0 1.2 0:32:56 postgres
456 root 20 0 103M 5M 3M S 0.1 0.2 0:15:23 sshd -D
123 root 20 0 97M 2M 1M S 0.0 0.0 0:01:45 systemd-udevd
1 root 20 0 23M 3M 2M S 0.0 0.1 0:02:34 systemd
234 messa 20 0 7M 2M 1M S 0.0 0.1 0:00:56 dbus-daemon
3456 root 0 -20 0B 0B 0B S 0.0 0.0 0:00:00 [kworker/0:0]

快捷键对比:

按键说明
F1 或 h打开帮助信息
F2 或 S打开设置菜单
F3 或 /搜索进程
F4 或 \按名称过滤进程
F5 或 t切换树形/列表视图
F6 或 < >改变排序列
F7 F8调整进程优先级 (nice值)
F9 或 k发送信号到进程
F10 或 q退出htop
L显示进程打开的文件和网络连接
I反转排序顺序
+ / -展开/折叠进程树

实战应用:

Terminal window
htop -u xiaoying # 只看xiaoying用户的进程
htop -t # 以树形显示进程关系
htop -p 2234 # 单独监视PID 2234这个进程
htop -s PERCENT_CPU # 按CPU使用率排序(降序)

三、进程控制核心命令#

3.1 信号系统详解#

Linux 操作系统的核心调度法则依赖于传递不同等级的控制信号量。

信号ID定义名场景特征是否可被捕捉
1SIGHUP挂起挂断:让服务无感平滑重载最新修改的配置文件(不彻底断开用户连接)✓ 可捕捉
2SIGINT中断信号:用户按 Ctrl+C 时发送,通知进程立即中断✓ 可捕捉
3SIGQUIT退出信号:用户按 Ctrl+\ 时发送,类似SIGINT但会生成核心转储文件✓ 可捕捉
9SIGKILL致命处决:绝对不可屏蔽捕捉的信号,在系统底层被强制剥夺生命周期✗ 不可捕捉
15SIGTERM温柔遣散:系统默认发送指令,允许进程在死前做完诸如持久化数据、清理缓存等收尾行为✓ 可捕捉
17/20SIGCHLD子进程状态变化:告知父进程子进程已退出或被暂停,用于僵尸进程回收✓ 可捕捉
19SIGSTOP暂停进程:暂停进程执行,不能被捕捉或忽略✗ 不可捕捉
18SIGCONT恢复进程:恢复被暂停的进程继续执行✓ 可捕捉

信号优先级使用策略:

  1. 优先使用 SIGTERM (15):给进程优雅退出的机会,释放资源
  2. 其次尝试 SIGINT (2):模拟 Ctrl+C,通常也能温和停止
  3. 最后才用 SIGKILL (9):强制杀死,但可能导致资源泄漏

[!CAUTION] 慎用极限击杀指令 在对业务核心数据库(如 MySQL/Redis/PostgreSQL)执行裁决操作时,必须避免直接投喂 kill -9!这种物理切断极易诱发致命的事务中断报错及持久化文件数据产生不可逆转甚至根本无法修复的物理级损坏现象。应先尝试 kill -15 或通过数据库客户端关闭。

3.2 进程控制指令群组运用#

3.2.1 kill 命令:基于PID精准击杀#

参数讲解表:

参数用途说明示例
-l列出所有可用的信号列表kill -l
-1 <PID>发送 SIGHUP 信号,让进程重新读取配置(平滑重启)kill -1 1234
-2 <PID>发送 SIGINT 信号,相当于 Ctrl+Ckill -2 1234
-9 <PID>发送 SIGKILL 信号,强制杀死进程(不可捕捉)kill -9 1234
-15 <PID>发送 SIGTERM 信号,温和请求进程退出(kill 默认值)kill -15 1234 或 kill 1234
-TERM <PID>同 -15,按信号名而非ID发送kill -TERM 1234
-STOP <PID>发送 SIGSTOP 信号,暂停进程执行kill -STOP 1234
-CONT <PID>发送 SIGCONT 信号,继续已暂停的进程kill -CONT 1234

模拟场景与命令:

kill_scenarios.sh
# 场景1:优雅停止Nginx服务(给它保存配置的机会)
kill -15 $(pgrep -f "nginx: master")
# 场景2:强制杀死多个java进程
kill -9 1234 5678 9012
# 场景3:平滑重载Nginx配置(不中断现有连接)
kill -1 $(pgrep -f "nginx: master")
# 场景4:暂停一个长时间运行的脚本
kill -STOP 2345
# 场景5:恢复暂停的脚本
kill -CONT 2345
# 场景6:列出所有可用信号
kill -l

3.2.2 pkill 命令:按名称或权限范围轰炸#

pkill 支持按照进程名称、用户、终端等属性批量操作进程,相比 kill 更加灵活。

参数讲解表:

参数全称用途说明示例
-u <user>user仅终止指定用户的进程pkill -u xiaoying
-U <user>real user按真实用户ID过滤(区分setuid程序)pkill -U root
-t <tty>terminal仅终止指定终端上的进程pkill -t pts/0
-xexact match启动严苛的字面精确匹配,避免误伤pkill -x java
-ffull匹配完整的命令行参数,不仅仅是程序名pkill -f "python app.py"
-g <pgrp>pgroup按进程组ID终止pkill -g 2048
-s <sid>session按会话ID终止(如终止整个SSH会话)pkill -s 1000
-P <ppid>parent pid按父进程ID终止该进程的所有子进程pkill -P 1234
-nnewest仅终止最新匹配的进程pkill -n nginx
-ooldest仅终止最旧的匹配进程pkill -o nginx
-llist列出匹配的进程但不终止(仅列表,不执行)pkill -l nginx
--signal <sig>signal指定发送的信号类型pkill --signal=TERM nginx

模拟场景与命令:

pkill_scenarios.sh
# 场景1:温和停止所有nginx进程(允许优雅退出)
pkill -15 nginx
# 场景2:强制杀死用户xiaoying的所有进程(紧急情况下隔离用户)
pkill -9 -u xiaoying
# 场景3:精确匹配java进程名,避免误杀包含java名的其他程序
pkill -x java
# 场景4:终止指定Python脚本(按完整命令行匹配)
pkill -f "python /home/xiaoying/app.py"
# 场景5:列出(不终止)所有匹配postgres的进程
pkill -l postgres
# 场景6:强制杀死某个SSH终端上的所有进程
pkill -9 -t pts/1
# 场景7:仅终止最新启动的nginx进程
pkill -n -15 nginx
# 场景8:按父进程ID终止其子进程(孤立某个服务)
pkill -P 456
# 场景9:使用正则表达式匹配(需要加上-f参数)
pkill -f "python.*app"

3.2.3 killall 命令:通过完整名称同名进程扫荡#

killall 与 pkill 类似,但仅支持按进程名称匹配,不支持更复杂的过滤条件。

参数讲解表:

参数全称用途说明示例
-u <user>user仅终止指定用户运行的进程killall -u xiaoying httpd
-gprocess group按进程组终止killall -g processname
-iinteractive交互模式,每个进程都要求确认killall -i nginx
-llist列出所有可用信号killall -l
-qquiet不输出详细信息killall -q nginx
-r <regex>regex使用正则表达式匹配进程名killall -r "java.*"
-s <signal>signal指定发送的信号killall -s TERM nginx
-vverbose显示详细的操作信息killall -v nginx
-9 / -KILLkill signal强制杀死(直接附加)killall -9 apache2

模拟场景与命令:

killall_scenarios.sh
# 场景1:温和停止所有apache2进程
killall -15 apache2
# 或简写为:
killall apache2
# 场景2:强制杀死所有httpd进程
killall -9 httpd
# 场景3:交互式终止(每个进程都要确认)
killall -i nginx
# 场景4:仅终止指定用户xiaoying的python进程
killall -u xiaoying python
# 场景5:使用正则表达式杀死所有java进程变种
killall -r "java.*"
# 场景6:安静模式,不输出操作信息
killall -q httpd
# 场景7:显示详细操作日志
killall -v nginx

三种进程杀取指令对比:

特性killpkillkillall
按PID精准杀取✓✗(需结合其他命令获取PID)✗
按进程名批量杀取✗✓✓
支持正则表达式✗✓✓ (部分支持)
按用户过滤✗✓✓
按TTY终端过滤✗✓✗
按父进程ID过滤✗✓✗
交互式确认✗✗✓
常见程度★★★★★★★★★☆★★★☆☆

3.3 pgrep / pidof 命令:快速查找进程ID#

当需要获取进程ID用于后续操作时,这两个命令极其高效。

3.3.1 pgrep 命令详解#

参数讲解表:

参数全称用途说明示例
-u <user>user仅查找指定用户的进程pgrep -u root nginx
-U <user>real user按真实用户ID过滤pgrep -U xiaoying
-g <pgrp>pgroup按进程组过滤pgrep -g 2048
-s <sid>session按会话ID过滤pgrep -s 1000
-P <ppid>parent pid找出指定父进程的所有子进程pgrep -P 1234
-llist同时显示进程名和PIDpgrep -l nginx
-afull显示完整的命令行pgrep -a java
-ffull在完整命令行中搜索,不仅仅是进程名pgrep -f "python app.py"
-xexact精确匹配进程名(完全相等)pgrep -x java
-nnewest返回最新匹配的进程的PIDpgrep -n nginx
-ooldest返回最旧匹配的进程的PIDpgrep -o nginx
-ccount统计匹配进程的数量pgrep -c nginx

模拟输出示例:

Terminal window
# 执行: pgrep nginx
1200
1201
1202
# 执行: pgrep -l nginx
1200 nginx
1201 nginx
1202 nginx
# 执行: pgrep -a java
2234 /usr/bin/java -Xmx512m -jar myapp.jar
# 执行: pgrep -c nginx
3
# 执行: pgrep -u xiaoying
1024
2234
2345
# 执行: pgrep -P 456
789
890
1000

实战应用:

Terminal window
# 快速获取nginx主进程PID并发送信号
kill -HUP $(pgrep -o nginx)
# 统计某个用户有多少个进程
pgrep -u xiaoying -c
# 列出所有python脚本进程
pgrep -l -f "python"
# 找出所有子进程
pgrep -P $(pgrep -o nginx)
# 获取最新的java进程并强制杀死
kill -9 $(pgrep -n java)

3.3.2 pidof 命令详解#

pidof 与 pgrep 功能相似但更简洁,主要用于快速查找进程ID。

参数讲解表:

参数全称用途说明示例
-ssingle仅返回一个PID(通常是最新的)pidof -s nginx
-xscripts也查找shell脚本(不仅仅是二进制程序)pidof -x bash
-o <pid>omit排除指定PID的结果pidof -o 1234 nginx

模拟输出示例:

Terminal window
# 执行: pidof nginx
1200 1201 1202
# 执行: pidof -s nginx
1202
# 执行: pidof java
2234
# 执行: pidof -x bash
2048 3002 4521

pgrep vs pidof 对比:

特性pgreppidof
过滤功能丰富程度★★★★★ (支持用户、TTY、进程组等)★★☆☆☆ (基础功能)
正则表达式支持✓✗
显示进程名✓ (加-l参数)✗
返回多个PID✓✓
仅返回单个PID✓ (加-n/-o参数)✓ (加-s参数)
常见程度★★★★☆★★★☆☆

四、后台进程运行与管理#

4.1 后台进程基础概念#

后台进程是指脱离终端控制、在系统后台运行的进程。掌握后台进程的运行方法对于服务器管理至关重要。

4.1.1 前台进程与后台进程的切换#

foreground_background.sh
# 方式1:在命令末尾加 & 使其运行在后台
sleep 300 &
# 方式2:在已运行的前台进程中按 Ctrl+Z 暂停,再使用 bg 命令转为后台运行
# 用户正在运行: sleep 300
# 按 Ctrl+Z
[1]+ Stopped sleep 300
bg 1 # 将暂停的作业转为后台运行
# 方式3:使用 fg 命令将后台进程调回前台
fg %1
# 方式4:查看当前终端的所有后台作业
jobs # 显示所有后台作业
jobs -l # 显示后台作业及其PID
jobs -r # 仅显示运行中的后台作业
jobs -s # 仅显示已停止的后台作业

模拟场景演示:

Terminal window
$ sleep 100 &
[1] 2345
$ sleep 200 &
[2] 2346
$ jobs
[1]- Running sleep 100 &
[2]+ Running sleep 200 &
$ fg %1
sleep 100
# 用户按 Ctrl+Z
^Z
[1]+ Stopped sleep 100
$ bg %1
[1]+ sleep 100 &
$ jobs -l
2345 Running sleep 100 &
2346 Running sleep 200 &
$ kill %2
[2]+ Terminated sleep 200
$ jobs
[1]- Running sleep 100 &

4.2 nohup 命令:免疫终端关闭的后台运行#

nohup (no hangup) 用于运行那些需要长期后台执行、且要免疫终端关闭信号的进程。

参数讲解表:

参数全称用途说明示例
(无参数)command需要运行的命令nohup python app.py
--helphelp显示帮助信息nohup --help
--versionversion显示版本信息nohup --version

核心特性:

  • 自动忽略 SIGHUP 信号(当终端关闭时不会被杀死)
  • 自动将标准输出重定向到 nohup.out 文件
  • 自动将标准错误也重定向到 nohup.out 文件

模拟场景与命令:

nohup_scenarios.sh
# 场景1:基础使用,让Python脚本在后台持续运行
nohup python /home/xiaoying/app.py &
# 场景2:自定义输出文件,而非默认的nohup.out
nohup python /home/xiaoying/app.py > /var/log/app.log 2>&1 &
# 场景3:在脚本中使用nohup运行多个后台任务
nohup bash -c '
python app1.py &
python app2.py &
wait
' > /var/log/tasks.log 2>&1 &
# 场景4:使用nohup运行一个需要长时间编译的任务
nohup ./configure --prefix=/usr/local && make && make install > build.log 2>&1 &
# 场景5:运行一个带参数的复杂命令
nohup java -Xmx512m -Xms512m -jar myapp.jar --config=/etc/myapp.cfg > /var/log/java.log 2>&1 &
# 检查进程是否仍在运行
ps aux | grep "python app.py"
# 查看输出日志
tail -f nohup.out # 实时查看
cat nohup.out # 查看全文

nohup 输出重定向详解:

Terminal window
# 标准用法:既捕捉标准输出,也捕捉错误输出
nohup command > output.log 2>&1 &
# 拆解说明:
# > output.log : 将标准输出(STDOUT, fd=1)重定向到output.log
# 2>&1 : 将标准错误(STDERR, fd=2)重定向到标准输出(&1),即也重定向到output.log
# & : 整个命令在后台执行
# 如果不想保留输出(仅在后台安静运行):
nohup command > /dev/null 2>&1 &
# 分别保存标准输出和错误输出到不同文件:
nohup command > stdout.log 2> stderr.log &

4.3 & 操作符:简单的后台运行#

& 是shell的内置操作符,用于将进程放入后台执行,但不能免疫SIGHUP信号(关闭终端时进程会被杀死)。

参数讲解表:

操作说明示例
command &将命令放入后台执行,立即返回提示符sleep 300 &
command1 & command2 &同时启动多个后台进程task1 & task2 & task3 &
(command1 & command2) &创建子shell并让其内的所有命令后台运行(python app1.py & python app2.py) &
command > /dev/null 2>&1 &后台运行并丢弃所有输出yes > /dev/null 2>&1 &

模拟场景与命令:

ampersand_scenarios.sh
# 场景1:简单的后台运行
sleep 300 &
# 模拟输出
# [1] 2345
# 返回提示符
# 场景2:同时启动多个后台任务
python task1.py & python task2.py & python task3.py &
# 场景3:让后台进程不占用终端输出
./long_running_task > /dev/null 2>&1 &
# 场景4:使用子shell管理多个相关任务
(while true; do echo "task 1"; sleep 10; done) & \
(while true; do echo "task 2"; sleep 10; done) &
# 场景5:后台运行编译任务(带进度输出)
make all > build.log 2>&1 &
# 查看后台作业
jobs
# 在前台等待后台作业完成
wait
# 等待特定的后台作业
wait %1
wait 2345
# 向后台作业发送信号
fg %1 # 将后台作业调回前台
kill %1 # 杀死第1个后台作业
kill %2 %3 # 同时杀死多个后台作业

关键警告:使用 & 运行的进程在终端关闭时会被SIGHUP信号杀死,因此在实际生产环境中应该使用 nohup 或其他工具。

4.4 screen 命令:虚拟终端管理#

screen 是一个功能强大的终端复用工具,可以创建多个虚拟终端会话,即使SSH连接断开,会话中的进程也能继续运行。

参数讲解表:

参数全称用途说明示例
-S <name>session-name创建命名会话screen -S myapp
-ddetach后台创建会话(不立即进入)screen -d -S worker
-r <session>reattach重新连接到已存在的会话screen -r myapp
-R <session>reattach-or-create连接或创建会话screen -R myapp
-lslist列出所有会话screen -ls
-x <session>multiplex多个用户共享同一个会话screen -x myapp
-D <session>force-detach强制断开其他连接,然后连接该会话screen -D -r myapp
-m <command>run-command直接运行命令不进入shellscreen -S test -m java -jar app.jar
-c <file>config使用指定的配置文件screen -c ~/.screenrc
-d -m <cmd>daemon mode后台运行命令screen -d -m python app.py
-wipecleanup清理已死亡的会话screen -wipe

模拟场景与命令:

screen_scenarios.sh
# 场景1:创建一个名为myapp的新会话并进入
screen -S myapp
# 场景2:在会话内运行一个长期任务
# (在screen会话内执行)
$ python /home/xiaoying/app.py
# 场景3:从会话内分离出来(回到原终端),会话继续运行
# 按 Ctrl+A,然后按 d
# 提示: [detached from myapp]
# 场景4:列出所有screen会话
screen -ls
# 输出示例:
# There are screens on:
# 3456.myapp (2025-01-09 10:30) (Detached)
# 3789.test (2025-01-09 10:25) (Attached)
# 2 Sockets in /run/screen/S-xiaoying.
# 场景5:重新连接到分离的会话
screen -r myapp
# 场景6:后台创建并运行任务(不进入会话)
screen -d -m -S worker python /home/xiaoying/worker.py
# 场景7:列出会话后,强制连接(如果有其他连接则断开它)
screen -D -r myapp
# 场景8:多个用户共享一个会话(协作调试)
# 用户1:
screen -d -m -S shared python app.py
screen -r shared
# 用户2:
screen -x shared
# 场景9:后台批量运行多个任务
screen -d -m -S task1 python task1.py
screen -d -m -S task2 python task2.py
screen -d -m -S task3 python task3.py
# 场景10:定期检查会话状态
for session in $(screen -ls | grep -oP '\d+\.\w+' | cut -d. -f2); do
echo "Session: $session"
screen -S $session -X hardcopy /tmp/screen_$session.log
done
# 场景11:清理所有已死亡的会话
screen -wipe

screen 内部快捷键:

快捷键功能说明
Ctrl+A, d分离当前会话(会话在后台继续运行)
Ctrl+A, c创建新的窗口(在同一会话内)
Ctrl+A, n切换到下一个窗口
Ctrl+A, p切换到上一个窗口
Ctrl+A, 0-9直接切换到指定窗口编号
Ctrl+A, "列出所有窗口,选择后跳转
Ctrl+A, A重命名当前窗口
Ctrl+A, k关闭当前窗口
Ctrl+A, S水平分割窗口
Ctrl+A, |竖直分割窗口
Ctrl+A, X关闭当前分割区域
Ctrl+A, Tab在分割区域间切换
Ctrl+A, ?显示帮助信息
Ctrl+A, :进入命令模式(输入screen命令)

4.5 tmux 命令:现代的终端复用工具#

tmux 是 screen 的现代替代品,提供了更灵活的布局、更好的配置和更直观的快捷键。

参数讲解表:

参数全称用途说明示例
new-session -s <name>new创建新会话tmux new-session -s myapp
new-window -n <name>new window在会话内创建新窗口tmux new-window -n editor
split-window -hhorizontal水平分割窗格tmux split-window -h
split-window -vvertical竖直分割窗格tmux split-window -v
attach-session -t <name>attach连接到指定会话tmux attach-session -t myapp
list-sessions / lslist列出所有会话tmux ls
list-windowswindows列出当前会话的所有窗口tmux list-windows
kill-session -t <name>kill关闭指定会话tmux kill-session -t myapp
kill-window -t <name>kill window关闭指定窗口tmux kill-window -t myapp:0
send-keys -t <target> <keys>send向指定窗口/窗格发送按键或命令tmux send-keys -t myapp "python app.py" Enter
new-session -d -s <name> <cmd>daemon后台创建会话并运行命令tmux new-session -d -s worker python app.py

tmux 会话/窗口/窗格的层级关系:

tmux Session (会话,一个独立的工作空间)
├── Window 1 (窗口1,可在会话内切换)
│ ├── Pane 1.1 (窗格,一个shell会话)
│ ├── Pane 1.2
│ └── Pane 1.3
├── Window 2
│ ├── Pane 2.1
│ └── Pane 2.2
└── Window 3
└── Pane 3.1

模拟场景与命令:

tmux_scenarios.sh
# 场景1:创建一个新的tmux会话
tmux new-session -s myapp
# 场景2:在后台创建会话并运行Python脚本
tmux new-session -d -s worker python /home/xiaoying/worker.py
# 场景3:列出所有tmux会话
tmux ls
# 输出示例:
# myapp: 3 windows (created Wed Jan 8 10:30:45 2025) [120x40]
# worker: 1 windows (created Wed Jan 8 10:32:15 2025) (detached) [120x40]
# 场景4:连接到指定会话
tmux attach-session -t myapp
# 场景5:在会话内创建新窗口并命名
tmux new-window -t myapp -n editor
# 场景6:在指定窗口内分割窗格(水平和竖直)
tmux split-window -t myapp:0 -h # 水平分割
tmux split-window -t myapp:0 -v # 竖直分割
# 场景7:在指定窗格运行命令(不进入交互式)
tmux send-keys -t myapp:0.0 "python app.py" Enter
tmux send-keys -t myapp:0.1 "tail -f /var/log/app.log" Enter
# 场景8:后台启动多个相关任务
tmux new-session -d -s dev
tmux send-keys -t dev "cd /home/xiaoying/project && npm install" Enter
tmux new-window -t dev -n server
tmux send-keys -t dev:server "npm run dev" Enter
tmux new-window -t dev -n logs
tmux send-keys -t dev:logs "tail -f logs/*" Enter
# 场景9:在特定窗格内执行多行命令
tmux send-keys -t myapp:0.0 "
cd /home/xiaoying/project
source venv/bin/activate
python app.py
" Enter
# 场景10:列出指定会话的所有窗口
tmux list-windows -t myapp
# 场景11:关闭指定会话
tmux kill-session -t myapp
# 场景12:关闭特定窗口
tmux kill-window -t myapp:1
# 场景13:批量查看和管理多个会话
for session in $(tmux ls -F "#{session_name}"); do
echo "=== Session: $session ==="
tmux list-windows -t $session
done

tmux 快捷键(默认前缀 Ctrl+B):

快捷键功能说明
Ctrl+B, d分离当前会话
Ctrl+B, c创建新窗口
Ctrl+B, n切换到下一个窗口
Ctrl+B, p切换到上一个窗口
Ctrl+B, l切换到上次使用的窗口
Ctrl+B, w列出所有窗口并选择
Ctrl+B, &关闭当前窗口(需确认)
Ctrl+B, ,重命名当前窗口
Ctrl+B, "竖直分割窗格
Ctrl+B, %水平分割窗格
Ctrl+B, o在分割窗格间循环
Ctrl+B, x关闭当前窗格
Ctrl+B, z放大/缩小当前窗格
Ctrl+B, [进入复制模式(可滚动查看历史)
Ctrl+B, ]粘贴复制的内容
Ctrl+B, :进入命令模式
Ctrl+B, ?显示所有快捷键帮助

nohup、&、screen、tmux 对比总结:

特性nohup&screentmux
简单易用程度★★★★★★★★★★★★★☆☆★★★★☆
免疫SIGHUP✓✗✓✓
支持多窗口/窗格✗✗✓✓
支持会话分离/重连✗✗✓✓
多用户协作✗✗✓✓
配置灵活性✗✗✓★★★★★
现代化程度✭✭★★★★★★★☆
用于长期后台服务★★★★★☆★★★★☆★★★★☆
用于交互式开发☆✗★★★★☆★★★★★

五、端口占用与网络连接(进程的网络资源)#

5.1 问题背景#

在日常运维工作中,经常会遇到”某个端口已被占用”的问题,导致服务无法启动。此时需要快速定位是哪个进程占用了该端口,然后决定是否杀死它或修改服务端口号。本章介绍三大神器:ss、netstat 和 lsof。

5.2 ss 命令:现代化的网络统计工具#

ss (socket statistics) 是新一代的网络连接查看工具,性能比 netstat 更好,功能更强大。

参数讲解表:

参数全称用途说明示例
-a / --allall sockets显示所有socket(包括监听和已建立连接)ss -a
-l / --listeninglistening仅显示处于监听状态的socketss -l
-t / --tcpTCP仅显示TCP协议的socketss -t
-u / --udpUDP仅显示UDP协议的socketss -u
-n / --numericnumeric显示IP地址和端口号(不进行DNS反向解析)ss -n
-p / --processprocess显示使用该socket的进程信息ss -p
-e / --extendedextended显示扩展信息(如接收缓冲、发送缓冲等)ss -e
-m / --memorymemory显示内存使用统计ss -m
-i / --infoinfo显示TCP内部信息(如RTO、重传次数等)ss -i
-s / --summarysummary显示统计摘要而非详细列表ss -s
-H / --no-headerno header不显示表头ss -H
-K / --killkill关闭符合条件的socket(需root权限)ss -K dst 192.168.1.100
--dport <port>dest port按目标端口过滤ss -t --dport :8080
--sport <port>source port按源端口过滤ss -t --sport :8080
-A <proto>protocol family指定协议族(inet、inet6、unix等)ss -A inet
dst <address>destination按目标地址过滤ss dst 192.168.1.100
src <address>source按源地址过滤ss src 192.168.1.100

最常用组合速记:

Terminal window
ss -tlnp # 显示所有监听的TCP端口及其进程(最常用!)
ss -tunap # 显示所有TCP和UDP连接及其进程
ss -s # 统计摘要
ss -t --dport :8080 # 查看占用8080端口的进程

模拟输出示例:

Terminal window
# 执行: ss -tlnp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=456,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1200,fd=6))
LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1200,fd=7))
LISTEN 0 100 127.0.0.1:3306 0.0.0.0:* users:(("mysqld",pid=2000,fd=20))
LISTEN 0 128 127.0.0.1:5432 0.0.0.0:* users:(("postgres",pid=890,fd=6))
LISTEN 0 100 0.0.0.0:8080 0.0.0.0:* users:(("java",pid=2234,fd=45))
# 执行: ss -tunap
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=456,fd=3))
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1200,fd=6))
ESTAB 0 0 192.168.1.100:22 192.168.1.1:54321 users:(("sshd",pid=2048,fd=3))
ESTAB 0 0 192.168.1.100:80 192.168.1.50:12345 users:(("nginx",pid=1201,fd=7))
TIME_WAIT 0 0 192.168.1.100:8080 192.168.1.51:54322
# 执行: ss -s
TCP: 7 ESTABLISHED 2 SYN-SENT 0 CLOSED 0 CLOSEWAIT 0 TIME-WAIT 8 CLOSE-PROXY 0 other 0
INET: 7 RECEIVED ACK 2 RECEIVED RST 0 RECEIVED ECN 0 SENT RST 1000 SEND-PROBES 100
InSegs: 12500
OutSegs: 10200

实战应用场景:

ss_practical_scenarios.sh
# 场景1:查看所有监听的端口及其进程(最常用!)
ss -tlnp
# 场景2:查看所有TCP连接及其进程(包括已建立和待连接状态)
ss -tunap
# 场景3:查看特定端口被谁占用
ss -t --dport :8080 # 查看8080端口
ss -t --dport :22 # 查看SSH端口
# 场景4:按照进程ID查找所有网络连接
ss -p | grep "pid=2234"
# 场景5:查看UDP监听端口(如DNS、NTP服务)
ss -ul
# 场景6:查看某个IP地址的所有连接
ss src 192.168.1.100
ss dst 192.168.1.200
# 场景7:查看socket统计(内存使用等)
ss -s
# 场景8:查看TCP连接状态统计(多少个ESTABLISHED、TIME_WAIT等)
ss -t -s
# 场景9:实时监控(每2秒更新一次)
watch -n 2 'ss -tlnp'
# 场景10:查找处于TIME_WAIT状态的连接(可能导致端口不可用)
ss -t state TIME-WAIT
# 场景11:查看某个用户的所有网络连接
ss -p | grep "xiaoying"
# 场景12:输出IPv6监听端口
ss -tlnp | grep -i ipv6

5.3 netstat 命令:经典的网络统计工具#

netstat 是传统的网络状态查看工具,在一些较老的Linux系统上仍然常用。虽然 ss 更现代,但 netstat 在某些场景下仍有用处。

参数讲解表:

参数全称用途说明示例
-a / --allall显示所有socketnetstat -a
-l / --listeninglistening仅显示监听状态netstat -l
-t / --tcpTCP仅显示TCPnetstat -t
-u / --udpUDP仅显示UDPnetstat -u
-n / --numericnumeric不进行DNS解析netstat -n
-p / --programprogram显示关联的进程PID和名称netstat -p
-e / --extendextend显示扩展信息netstat -e
-s / --statisticsstatistics显示统计汇总netstat -s
-r / --routeroute显示路由表netstat -r
-i / --interfacesinterfaces显示网络接口统计netstat -i
-g / --groupmulticast显示多播组netstat -g
-M / --masquerademasquerade显示伪装连接netstat -M
-c / --continuouscontinuous持续更新输出(每秒刷新)netstat -c

最常用组合速记:

Terminal window
netstat -tlnp # 显示所有监听的TCP端口及进程
netstat -tunap # 显示所有TCP和UDP连接
netstat -s # 统计摘要
netstat -r # 显示路由表

模拟输出示例:

Terminal window
# 执行: netstat -tlnp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 456/sshd
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1200/nginx
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 1200/nginx
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 2000/mysqld
tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN 890/postgres
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 2234/java
# 执行: netstat -s
Ip:
Forwarding: 0
12500 total packets received
0 forwarded
0 incoming packets discarded
12500 incoming packets delivered
10200 requests sent out
...
Tcp:
200 active connections openings
150 passive connection openings
50 failed connection attempts
...

实战应用场景:

netstat_practical_scenarios.sh
# 场景1:查看所有监听的TCP端口
netstat -tlnp
# 场景2:查看所有已建立的TCP连接
netstat -tp | grep ESTABLISHED
# 场景3:查看路由表
netstat -r
# 场景4:显示网络接口统计
netstat -i
# 场景5:统计TCP状态分布
netstat -an | grep -i tcp | awk '{print $NF}' | sort | uniq -c | sort -rn
# 场景6:监控实时网络连接(每秒更新)
netstat -c
# 场景7:查看某个端口的所有连接
netstat -tulnp | grep :8080
# 场景8:查看处于TIME_WAIT状态的连接数
netstat -an | grep TIME_WAIT | wc -l
# 场景9:显示全部网络统计信息
netstat -s
# 场景10:查看某个用户的网络连接
netstat -tulnp | grep username

5.4 lsof 命令:查看进程打开的文件和网络连接#

lsof (list open files) 是最强大的文件和网络连接查看工具,可以显示进程打开的所有文件、socket等。

参数讲解表:

参数全称用途说明示例
-iinternet显示网络连接lsof -i
-i:<port>port显示指定端口的连接lsof -i:8080
-i<protocol>protocol指定协议(TCP、UDP)lsof -iTCP -sTCP:LISTEN
-p <pid>process显示指定PID的进程打开的文件lsof -p 2234
-u <user>user显示指定用户的进程打开的文件lsof -u xiaoying
-c <command>command显示指定命令名的进程打开的文件lsof -c nginx
-d <fd>file descriptor显示指定文件描述符lsof -d 3,4,5
-aand逻辑AND组合多个条件lsof -i:8080 -a -p 2234
+d <dir>directory显示某个目录下被打开的文件lsof +d /var/log
-n / -Pnumeric不进行DNS/服务名解析lsof -n -i
-s <state>state按状态过滤lsof -i -s TCP:LISTEN
-tterse仅输出PID(简洁模式)lsof -t -i:8080
+Llost显示已删除但仍被进程占用的文件lsof +L
+D <dir>recursive递归显示目录内被打开的文件lsof +D /var

最常用组合速记:

Terminal window
lsof -i:8080 # 查看占用8080端口的进程
lsof -i TCP:LISTEN # 显示所有监听的TCP端口
lsof -p 2234 # 查看PID为2234的进程打开的所有文件
lsof -u xiaoying # 查看用户xiaoying打开的所有文件

模拟输出示例:

Terminal window
# 执行: lsof -i:8080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 2234 xiaoying 45u IPv4 0x12345678 0t0 TCP *:8080 (LISTEN)
curl 12345 xiaoying 15u IPv4 0x87654321 0t0 TCP 192.168.1.100:54321->10.0.0.1:8080 (ESTABLISHED)
# 执行: lsof -i TCP:LISTEN
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 456 root 3u IPv4 0x11111111 0t0 TCP *:22 (LISTEN)
nginx 1200 root 6u IPv4 0x22222222 0t0 TCP *:80 (LISTEN)
nginx 1200 root 7u IPv4 0x33333333 0t0 TCP *:443 (LISTEN)
mysqld 2000 mysql 20u IPv4 0x44444444 0t0 TCP 127.0.0.1:3306 (LISTEN)
postgres 890 post 6u IPv4 0x55555555 0t0 TCP 127.0.0.1:5432 (LISTEN)
java 2234 xiao 45u IPv4 0x66666666 0t0 TCP *:8080 (LISTEN)
# 执行: lsof -p 2234
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 2234 xiaoying cwd DIR 0,18 4096 13107203 /home/xiaoying/myapp
java 2234 xiaoying txt REG 0,18 5234567 13107456 /usr/bin/java
java 2234 xiaoying mem REG 0,18 12345678 13108000 /usr/lib/jvm/java/lib/server/libjvm.so
java 2234 xiaoying 0u CHR 1,3 0t0 1026 /dev/null
java 2234 xiaoying 1u REG 0,18 1234567 13109000 /var/log/app.log
java 2234 xiaoying 2u REG 0,18 1234567 13109000 /var/log/app.log
java 2234 xiaoying 3u IPv4 0x12345678 0t0 TCP *:8080 (LISTEN)
java 2234 xiaoying 10u unix 0xabcdef12 0t0 FILE /tmp/java-socket
...

输出字段详解:

字段示例含义
COMMANDjava, nginx进程的命令名
PID2234, 1200进程ID
USERxiaoying, root进程所属用户
FD3, 45u, cwd文件描述符(u表示读写,r表示读,w表示写;cwd表示当前工作目录)
TYPEIPv4, REG, DIR, CHR文件类型(IPv4/IPv6网络、普通文件、目录、字符设备等)
DEVICE0,18, 0x123设备号
SIZE/OFF4096, 0t0文件大小或偏移
NODE/dev/null, TCP *:8080inode号或网络信息
NAME/home/xiaoying/myapp文件或网络连接的完整名称

实战应用场景:

lsof_practical_scenarios.sh
# 场景1:查看占用8080端口的进程(最常用!)
lsof -i:8080
# 场景2:查看所有监听的TCP端口
lsof -i TCP:LISTEN
# 场景3:查看所有已建立的TCP连接
lsof -i TCP -s TCP:ESTABLISHED
# 场景4:查看某个进程打开的所有文件和网络连接
lsof -p 2234
# 场景5:查看某个用户的所有打开文件和网络连接
lsof -u xiaoying
# 场景6:查看某个命令关联的进程打开的文件
lsof -c nginx
# 场景7:查看某个特定文件被哪些进程打开
lsof /var/log/app.log
# 场景8:仅输出占用8080端口的进程PID(用于管道)
lsof -t -i:8080
# 场景9:查看已删除但仍被占用的文件(排查磁盘空间泄漏)
lsof +L 1
# 场景10:查看某个目录被打开的文件
lsof +d /var/log
# 场景11:实时监控网络连接(每2秒更新)
watch -n 2 'lsof -i TCP:LISTEN'
# 场景12:查看占用某个端口的进程并直接杀死
kill -9 $(lsof -t -i:8080)
# 场景13:统计进程打开的文件描述符数量(用于排查FD泄漏)
lsof -p 2234 | wc -l
# 场景14:查看最多打开文件数的进程
lsof | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# 场景15:查看网络连接统计(不同状态的连接数)
lsof -i -s TCP:LISTEN,ESTABLISHED,TIME_WAIT

5.5 三大工具对比总结#

特性ssnetstatlsof
显示监听端口✓ 推荐✓✓
显示已建立连接✓✓✓
显示进程信息✓✓✓
按端口过滤✓✗✓ 推荐
按进程过滤✗✗✓ 推荐
显示打开的文件✗✗✓ 仅此工具
性能★★★★★ (最快)★★★☆☆★★☆☆☆
现代化程度★★★★★★★☆☆☆★★★☆☆
在新系统推荐度★★★★★★★☆☆☆★★★★☆

5.6 快速定位端口占用的完整流程#

find_port_occupation.sh
#!/bin/bash
# 快速查找占用指定端口的进程并处理
PORT=${1:-8080}
echo "=== 查找占用端口 $PORT 的进程 ==="
# 方法1:使用lsof(推荐,最直观)
echo -e "\n【方法1:使用lsof】"
lsof -i :$PORT
# 方法2:使用ss
echo -e "\n【方法2:使用ss】"
ss -tlnp | grep :$PORT
# 方法3:使用netstat
echo -e "\n【方法3:使用netstat】"
netstat -tulnp | grep :$PORT
# 获取PID并交互式处理
echo -e "\n=== 处理选项 ==="
PID=$(lsof -t -i:$PORT)
if [ -z "$PID" ]; then
echo "❌ 未找到占用端口 $PORT 的进程"
exit 1
fi
echo "✓ 找到进程: PID=$PID"
ps -p $PID
echo -e "\n选择操作:"
echo "1) 查看进程详细信息"
echo "2) 正常终止进程 (kill -15)"
echo "3) 强制杀死进程 (kill -9)"
echo "4) 不做处理"
read -p "请输入选择 [1-4]: " choice
case $choice in
1)
lsof -p $PID
;;
2)
kill -15 $PID
echo "已发送SIGTERM信号,等待3秒..."
sleep 3
if ps -p $PID > /dev/null; then
echo "⚠ 进程仍在运行,尝试强制杀死"
kill -9 $PID
fi
echo "✓ 进程已终止"
;;
3)
kill -9 $PID
echo "✓ 进程已强制杀死"
;;
4)
echo "未进行任何操作"
;;
*)
echo "❌ 无效选择"
exit 1
;;
esac

六、排查与干预最佳实践#

[!TIP] 标准化操作链路

  1. 生命周期敬畏:永远优先使用 15 号信号请求进程自行退位,给它保留体面的权力。
  2. 僵尸巡检制度:通过 ps aux | grep Z 搭配定时巡检进行存量清零,不要让垃圾堆砌成为服务假死的暗雷。
  3. 批量裁决效率:当你面对大规模的并行任务池且需要重置时,使用 pkill 可以杜绝低效的查阅 PID 循环。
  4. CPU过载救援SOP:
    • 敲击 top 进入或使用 htop 进行实时观测。
    • 视线锁定首行 load average,判断是否超过CPU核心数。
    • 键入 P 或 M(按CPU或内存排序),找出罪魁祸首。
    • 若眼见 %wa 数值飙升(超过15%),请立刻转移视线去重点排查磁盘IO瓶颈。
  5. 网络连接排查SOP:
    • 使用 ss -tlnp 快速查看所有监听端口。
    • 使用 lsof -i:PORT 定位占用特定端口的进程。
    • 使用 lsof -p PID 查看进程打开的所有文件和连接。
    • 对于异常连接,先排查防火墙规则,再考虑杀死进程。

6.1 典型场景实战演练#

场景1:启动服务时提示”Address already in use”#

Terminal window
# 问题:Nginx无法启动,提示8080端口被占用
# 第1步:查找占用端口的进程
lsof -i:8080
# 输出: java ... TCP *:8080 (LISTEN)
# 第2步:查看该进程的详细信息
ps -p 2234 -o pid,ppid,user,%cpu,%mem,comm,args
# 输出: PID=2234, 占用内存3.5%, 是之前启动的java应用
# 第3步:决策:如果是旧进程则杀死,如果还需要则改变服务端口
kill -15 2234
sleep 2
# 验证是否成功
lsof -i:8080
# 无输出说明成功,可启动Nginx了

场景2:系统负载过高,CPU接近100%#

Terminal window
# 第1步:进入htop查看实时进程
htop
# 第2步:按P键按CPU使用率排序,找到占用最多的进程
# 发现: java进程占用55% CPU
# 第3步:查看该java进程的详细信息和网络连接
lsof -p 2234 | head -20
# 第4步:决策分析
# - 如果是业务应用,查看是否有死循环或内存溢出
# - 如果是异常进程,直接kill -9
# - 如果需要保留,考虑优化代码或增加资源
kill -15 2234

场景3:内存泄漏导致内存持续增长#

Terminal window
# 第1步:使用top或htop监控内存趋势
watch -n 5 'ps aux | grep java | head -5'
# 第2步:查看进程打开的文件(可能文件描述符泄漏)
lsof -p 2234 | wc -l
# 如果数字远大于正常值(如>1000),则可能是FD泄漏
# 第3步:查看已删除但被进程占用的文件
lsof -p 2234 | grep deleted
# 若有输出,说明磁盘空间被泄漏占用
# 第4步:决策:重启该进程释放资源,同时排查代码问题
systemctl restart myapp

场景4:终端SSH连接慢,响应迟缓#

Terminal window
# 第1步:检查网络连接状态
ss -tunap | grep ESTABLISHED | wc -l
# 若数值很大(如>10000),说明有大量连接堆积
# 第2步:查看TIME_WAIT状态的连接
ss -tan state TIME-WAIT | wc -l
# 第3步:查找占用SSH端口的进程
ss -tlnp | grep :22
lsof -i:22
# 第4步:检查是否有异常的大量SSH连接尝试
ss -tan | grep :22 | wc -l
# 第5步:如果是DDoS攻击,可以:
# - 限制并发连接数(iptables规则)
# - 关闭不必要的服务
# - 分析日志找出攻击源

场景5:守护进程(如Nginx)在后台运行但无法正常重启#

Terminal window
# 第1步:查看Nginx相关进程
ps aux | grep nginx
pgrep -a nginx
# 第2步:强制终止所有nginx进程
pkill -9 nginx
# 第3步:等待一秒,确保进程完全退出
sleep 1
# 第4步:验证进程已退出
pgrep nginx # 无输出说明成功
# 第5步:重新启动nginx
systemctl start nginx
# 或
nginx -s start
# 第6步:验证启动成功
lsof -i:80
ss -tlnp | grep nginx

总结#

本文深入讲解了Linux进程管理的核心技能:

  1. 进程基础:理解进程分类、PID概念、孤儿进程与僵尸进程的原理
  2. 查看工具:掌握 ps、pstree、top、htop 等进程查看命令
  3. 控制命令:灵活运用 kill、pkill、killall 等进程控制命令
  4. 快速定位:使用 pgrep 和 pidof 快速查找进程
  5. 后台运行:理解 nohup、&、screen、tmux 等后台管理工具的差异和应用
  6. 网络诊断:掌握 ss、netstat、lsof 等端口和网络连接查看工具
  7. 最佳实践:遵循”优先级递进、体面优先、数据安全第一”的运维哲学

掌握这些技能后,你将能够:

  • 快速定位和解决进程相关的各类问题
  • 优雅地管理后台进程和长期运行的任务
  • 诊断端口占用和网络连接问题
  • 在生产环境中安全、高效地进行进程控制

记住:在Linux系统中,进程是一切的基础。掌握进程管理就掌握了系统运维的核心。

Linux基础(7):Linux进程管理体系详解
https://www.6ixblog.site/posts/linux-basic-7/
作者
Licwic
发布于
2025-01-08
许可协议
CC BY-NC-SA 4.0