ARTICLE DETAIL

资讯详情

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

Linux软件包与进程管理实战:从命令到排错全攻略

Linux软件包与进程管理实战:从命令到排错全攻略 刚接触 Linux 的人最容易陷入一个误区抱着命令手册背了一堆ls、cd、cp结果真到了使用场景装软件装不上程序跑起来卡死想关关不掉最后只能重启机器。我在带新人或者帮朋友排查服务器问题时发现九成以上的日常故障最后都落在两件事上——软件包管理和进程管理。这两个能力搞扎实了Linux 才算是真正入了门。这篇文章就把这两块的核心命令、底层逻辑和实战排错一条条讲清楚覆盖从 Debian 系到 RedHat 系、从软件安装到进程调度适合刚上手的初学者也适合准备运维或开发面试时系统梳理知识点的同学。1. 装软件前先分清派系apt、yum、pacman用错命令等于白干1.1 为什么 Linux 装软件不像 Windows 那样双击Windows 的安装包是.exe或.msi双击运行一路点下一步就完事。但 Linux 的软件安装方式完全不同你面对的不是一个自解压程序而是一个软件包。软件包本质上是把程序本体、配置文件、依赖库、文档按特定格式打包在一起的文件集合。安装的过程实际上是包管理器把里面的文件解压到系统指定目录同时注册依赖关系、写入元数据的操作。不理解这件事就会出现一个经典场景下载了一个.deb或.rpm文件双击或用dpkg -i强装结果报依赖缺失然后就开始手工找依赖包装一个又报缺另一个陷入依赖地狱。这就是没搞明白 Linux 软件包管理的设计逻辑包之间是互相依赖的包管理器就是帮你自动处理这些依赖的管家。所以学会用对包管理器比背一百个命令都管用。1.2 Debian 系apt 是日常dpkg 是底层Debian 系Debian、Ubuntu、Deepin、Linux Mint 等使用的是dpkgAPT这套体系。dpkg是底层包处理工具能安装本地.deb文件但不处理远程仓库和自动依赖。aptAdvanced Package Tool是建立在dpkg之上的一层仓库管理工具它从软件源服务器拉取包列表自动计算依赖关系再调用dpkg完成安装。所以你在 Ubuntu 上最常用的命令是这样一套sudo apt update # 更新软件源索引 sudo apt upgrade # 升级所有可升级的包 sudo apt install nginx # 安装 nginx自动解决依赖 sudo apt remove nginx # 卸载 nginx保留配置文件 sudo apt purge nginx # 卸载 nginx同时清除配置 sudo apt autoremove # 清理不再需要的依赖包用 apt 时最容易被忽略的是第一步update。很多人从网上抄来apt install命令直接敲报错Unable to locate package于是四处找原因。本质很简单你的系统里还没有可用的软件索引包管理器根本不知道有这个包存在。update做的事就是去源服务器拉取最新的包列表相当于给超市建商品目录商品目录都没有你怎么结账1.3 RedHat 系yum 退役dnf 接力CentOS、RHEL、Fedora、Rocky、AlmaLinux 用的是rpmyum/dnf体系。rpm类似dpkg是底层打包工具yum是老一代包管理器在 RHEL 8 / CentOS 8 之后被dnf取代。dnf 可以和 yum 混用很多老教程里的yum install在新系统上依然能跑是因为做了兼容。sudo dnf update # 更新源索引 sudo dnf install nginx # 安装 sudo dnf remove nginx # 卸载 sudo dnf history # 查看安装历史 sudo dnf provides /usr/bin/nginx # 反查命令由哪个包提供我个人觉得 RedHat 系有个特别好用的点dnf provides命令可以反查一个文件或命令属于哪个软件包。比如你在服务器上发现有个二进制文件/usr/bin/somecmd不知道是哪个 rpm 包装出来的一条命令就能查到来源排查时特别实用。1.4 Arch 系与源码安装什么时候需要它们Arch 系的pacman是另一套逻辑命令很短上手后清爽得令人上瘾sudo pacman -Syu # 同步源并升级系统 sudo pacman -S nginx # 安装 sudo pacman -R nginx # 卸载但 Arch 系装软件最出名的是 AUR 仓库严格说那不算标准软件包而是从源码编译或拉取其他来源的脚本集合。源码编译安装./configure make make install在现代 Linux 桌面场景下已经不常用了除非是特定开发环境或 Alpine 那种极简系统。我自己只有遇到软件仓库里没有的版本、需要自定义编译参数时才会走源码这条路。日常使用优先走官方源这是避免依赖地狱的第一原则。下面这张表可以收藏遇到不同系统直接对照用途Debian/UbuntuCentOS/RHEL/FedoraArch更新索引apt updatednf updatepacman -Sy安装apt install 包名dnf install 包名pacman -S 包名卸载apt purge 包名dnf remove 包名pacman -R 包名搜索apt search 关键词dnf search 关键词pacman -Ss 关键词查看已装dpkg -lrpm -qapacman -Q2. 软件包全生命周期操作从搜索、安装到卸载清理的完整闭环2.1 装软件前先做光合作用update、upgrade、dist-upgrade 的边界很多人不理解update和upgrade的区别我换个说法apt update是光合作用把阳光远程仓库的索引吸收进来apt upgrade是生长,基于新已有的索引把已安装的软件升级。没有光合作用谈生长就是空谈。新手经常只执行 upgrade 不执行 update结果系统显示没有可升级的软件包还以为是软件源坏了。dist-upgrade比upgrade更进一步它会处理升级过程中出现的依赖变化可能需要卸载旧包或安装新依赖。在 Debian/Ubuntu 上做版本升级时dist-upgrade更彻底。但是生产服务器上我一般不主动跑dist-upgrade因为依赖变化带来的连锁升级可能导致某些服务行为改变。先备份、再升级这是运维的底线。2.2 搜索与安装别只会安装会搜包才是效率利器apt search nginx # 搜索软件源里名字包含 nginx 的包 apt show nginx # 查看某个包的详细信息 apt list --installed # 列出所有已安装的包apt show非常值得养成习惯安装前看一眼版本号、依赖项、安装大小可以避免装上之后发现版本不对。版本锁定也是运维常用手段apt install nginx1.18.0-0ubuntu1.3 # 指定版本安装 # 防止 apt 自动升级指定包 sudo apt-mark hold nginx我踩过一个真实的坑有一次在 Ubuntu 服务器上没锁定 nginx 版本某天执行 upgrade 后nginx 从 1.18 跳到 1.24配的第三方模块因为不兼容直接加载失败服务起不来。从那以后凡是生产环境里有关键第三方模块的软件我都先用apt-mark hold锁版本确认新版本测试通过后再解锁升级。2.3 卸载不是简单删文件remove、purge、autoremove 各有分工这是新手最容易搞混的一组命令。apt remove只卸载程序本体配置文件保留在/etc下apt purge连配置文件一起删autoremove是清理孤儿依赖也就是当初为满足某个包而自动装进来、现在已无用的依赖库。正确卸载流程应该是# 第一步停止服务 sudo systemctl stop nginx # 第二步卸载程序并清除配置 sudo apt purge nginx # 第三步清理孤儿依赖 sudo apt autoremove # 第四步如果确认无残留删掉手动创建的数据目录 sudo rm -rf /var/www/html为什么我要强调先停服务再卸载因为运行中的进程会保持文件句柄卸载时包管理器虽然有处理机制但服务如果正在写入数据可能产生不完整状态。停服务、卸载、清理、确认这套流程在数据库、Web 服务器这类有状态的服务上尤其重要。2.4 依赖冲突与软件包似乎无效离线安装 deb/rpm 的三大坑有时候需要离线安装下载好.deb或.rpm文件后用dpkg -i或rpm -ivh安装。我遇到最多的报错是软件包似乎无效或Error: dependency is not satisfiable。这三个原因占 99%架构不对你下载的是amd64机器是arm64或反之。用uname -m先确认架构。依赖缺失本地包依赖某个库但系统没装。Debian 系可以事后补救sudo apt-get install -f这个命令会自动修复损坏的依赖关系RedHat 系则用sudo dnf install ./包名.rpm直接让 dnf 处理本地包依赖。签名问题非官方源打包的软件没有对应的公钥或者包本身是坏的下载不完整。先检查文件file 包名.deb确认格式没问题。第三点补充一个技巧离线环境没有网络咋办在能联网的同版本机器上把依赖包全部下载下来# 在联网机器上 apt download nginx apt-get download $(apt-cache depends nginx | grep Depends | awk {print $2})下载好之后拷贝到离线机器用dpkg -i *.deb一次装完。如果包的版本一致、架构一致这套流程基本不会有问题。2.5 换源解决无法定位软件包和速度慢的终极手段无法定位软件包这个报错除了没执行update之外最常见的就是软件源配置有问题。国内用户经常碰到官方源连接超时或速度极慢解决办法是换成镜像源。Debian/Ubuntu 系的源配置文件在/etc/apt/sources.list或/etc/apt/sources.list.d/目录下。改源之前一定先备份sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak以 Ubuntu 为例修改源文件把域名换成镜像站常见的http://archive.ubuntu.com/ubuntu/改成http://mirrors.aliyun.com/ubuntu/或其他镜像路径注意 codename如 jammy、noble要保持一致然后执行sudo apt update验证。RedHat 系的源配置在/etc/yum.repos.d/目录下每个.repo文件对应一个仓库。要换源修改baseurl字段即可。这里有个值得注意的细节很多镜像源只支持http你如果系统配置了严格的安全策略可能还需要调整。另外不同发行版的镜像站路径命名规则不一样建议直接去镜像站页面看帮助文档每个大镜像站阿里、清华、中科大都有对应的配置向导照着复制粘贴比手写靠谱得多。3. 进程不是程序先建立这几个概念模型再敲命令3.1 程序与进程一个写在磁盘一个活在内存程序是一个静态的文件躺在磁盘里比如/usr/bin/nginx这个二进制文件。当你把它加载进内存、分配了运行所需的资源、拥有了自己独立的文件描述符和内存空间它才算一个进程。这个区分看起来很理论实际上对排错有直接帮助。比如你kill一个进程后内存没释放干净或者 CPU 还持续被占用多半是程序本身没处理好信号再比如磁盘上明明有某个程序但ps里找不到对应进程说明它根本没被启动或启动后立即退出。静态的程序和动态的进程在 Linux 的世界里是两码事。3.2 PID、PPID 与 forkLinux 是怎么生出进程的每个进程都有一个唯一 ID 叫 PID有父进程父进程的 ID 就是 PPID。Linux 创建新进程的机制是fork()一个进程调用 fork 会复制出几乎一模一样的子进程然后子进程再调用exec()去加载新的程序代码。这就是一切皆文件、进程靠 fork的底层逻辑。启动一台 Linux 机器后第一个进程是PID 1通常是systemd或init它是所有进程的祖先。用pstree命令查看你能看到整棵进程树systemd─┬─networkd ├─nginx───2*[nginx worker] └─sshd───sshd───bash───ps理解这棵树很重要。一个 Web 服务长挂不倒靠的不是主进程一个人而是主进程 fork 出来的 worker 进程在处理真正的请求。如果你把主进程 kill 掉worker 进程往往会被系统接管或跟着退出反过来你有nginx worker进程的资源占用异常光 kill worker 是没用的主进程会拉起新的 worker你得先搞清控制关系。3.3 前台、后台与守护进程nohup 和 到底做了什么在终端里敲nginx并回车这个进程会占据当前终端终端不能再输入别的命令这就是前台进程。按CtrlZ可以挂起任务用bg让它转后台继续跑sleep 300 # 前台卡住终端 # 按 CtrlZ 挂起然后输入 bg 转入后台 bg jobs # 查看当前终端的后台任务更常见的做法是命令后加直接放后台nginx 。但这样有一个坑后台进程仍然和当前终端会话绑定终端一关闭进程就可能收到 SIGHUP 信号被杀掉。所以真正的远程长驻任务要用nohupnohup ./myserver app.log 21 nohup的作用是让进程忽略 SIGHUP 信号终端关闭了进程也不影响运行。 app.log 21是把标准输出和错误输出都重定向到日志文件这样进程就算有问题也能在日志里留下痕迹。用完这个命令我不推荐真把进程丢那儿不管建议配合下面的pgrep、ps定期检查状态。守护进程是更高阶的存在比如sshd、mysqld它们脱离终端会话通常由systemd管理。操作它们要用systemctlsudo systemctl start mysqld # 启动服务 sudo systemctl enable mysqld # 开机自启 sudo systemctl status mysqld # 查看服务状态systemd引入了会话的概念和传统的nohup模式略有交叉但理解成由系统统一托管的守护进程管理模式即可。日常排查服务问题时systemctl status比直接ps看进程更直观它能直接告诉你服务处于 active 还是 failed 状态。3.4 僵尸进程与孤儿进程面试常问但很多人说不清这两个概念是 Linux 面试的高频题也是实际排错中会遇到的事。僵尸进程zombie是指子进程已经终止但父进程没有调用wait()回收它的退出状态导致这个子进程在进程表里残留占位。ps里显示为Z状态的进程就是僵尸。它不算真正运行不占 CPU 也不占内存但会占一个 PID 数量堆积多了进程表会耗尽。孤儿进程orphan是父进程先退出子进程被initPID 1 / systemd收养。孤儿进程本身不可怕甚至算是系统的自我保护机制关键是你得能区分这两个概念。我见过有人把系统里所有僵尸进程kill -9一顿乱杀结果根本杀不掉——僵尸进程已经死了杀掉它的办法是杀掉它的父进程或者等父进程wait它。所以排查僵尸进程的正确命令链是# 找出所有僵尸进程及其 PID ps aux | awk $8Z || $8Z {print} # 查看僵尸进程的父进程 PPID ps -o pid,ppid,stat,cmd -p 1234 # 处理父进程确认无业务后或通知程序正确 wait 子进程4. 进程查看与调度ps、top、kill 三板斧的高阶用法4.1 ps 输出里的每一列不要只会 ps auxps aux是全系统所有进程的完整快照几乎人人都会用。但很多人不知道每一列到底代表什么USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 168572 13576 ? Ss Jul01 0:11 /sbin/init www-data 25663 1.2 0.5 512984 42112 ? S 09:12 0:03 nginx: worker%CPU和%MEM是瞬时占用比例VSZ是虚拟内存大小RSS是常驻物理内存大小RSS 越大说明实际吃内存越多STAT表示进程状态S是睡眠R是运行Z是僵尸T是停止第一列里的表示前台进程TIME是进程累计消耗的 CPU 时间这个值很重要如果它持续增加但业务无响应基本可以断定有死循环或逻辑阻塞ps -ef和ps aux略有不同但核心信息一致。我更推荐养成用ps -eo pid,ppid,user,%cpu,%mem,stat,cmd --sort-%cpu的习惯按 CPU 从高到低排序真正排查问题时一眼看到罪魁祸首。4.2 top 里的 load average 和高负载数字多少才算不对劲top是动态刷新视图第一行输出的load average是很多人的知识盲区load average: 5.23, 4.86, 4.10这三个数字分别表示过去 1 分钟、5 分钟、15 分钟的系统负载。简单理解就是当前有多少任务在等待 CPU 处理。单核 CPU 的负载超过 1 就说明繁忙四核超过 4 同样说明繁忙。负载虚高最常见的两个原因不是 CPU 不够而是进程阻塞在 IO 等待或者有进程在疯狂占用磁盘读写。在 top 界面里按1可以查看每个 CPU 核心的使用情况按M按内存排序P按 CPU 排序k可以直接输入 PID 发信号。但我现在更推荐用htop它的显示更直观还能用鼠标点击排序。Ubuntu 上装一下就好sudo apt install htop。4.3 kill 的本质是发信号为什么 kill -9 是最后手段kill命令名有误导性它真正的功能是向进程发送信号。不同信号有不同的含义信号编号作用SIGHUP1挂起常用于通知守护进程重载配置SIGINT2终端中断等价于 CtrlCSIGTERM15请求终止进程可以捕获并清理后退出SIGKILL9强制杀死进程无法捕获必须立即结束正确顺序是先killSIGTERM让进程有清理资源、保存状态的机会不行再kill -9SIGKILL。kill -9直接把进程的善后机会剥夺了可能导致数据损坏。在 Java 应用、数据库这类有状态的进程上尤其要避免一上来就-9。还有一个命令叫pkill按名字匹配杀进程pkill -f python app.py。但pkill危险在于匹配规则太宽比如你pkill -f python可能把系统里所有带 python 字样的进程全杀了。用之前先pgrep -f python app.py看命中了哪些 PID确认没有误伤再执行。4.4 端口与进程的关联找出8080 端口被谁占了这是在实际工作中用到最频繁的一组命令之一。无论是启动服务时报端口已绑定还是排查可疑占用思路都一样# 查看端口占用和应用 ss -tlnp | grep 8080 # 如果有 lsof也可以这么查 lsof -i :8080 # 拿到 PID 后看进程明细 ps -fp 12345ss是现代 Linux 上替代netstat的工具-t显示 TCP-l显示监听端口-n不解析服务名-p显示进程信息。我见过有人装了 net-tools 专门用netstat其实ss命令本身就在 iproute2 包里绝大多数系统自带了。这里分享一个小技巧如果一个端口被系统保留了显示被根进程占用但 PID 是 1那大概率是权限问题比如普通用户想监听 80 端口会报权限不足如果你看到端口被一个不存在于ps里的进程占用那可能是网络命名空间或容器相关的绑定需要sudo ss -tlnp重新查看完整信息。5. 三条实战排错链路从软件包报错到进程突然消失5.1 无法定位软件包的完整排查思路这个报错我帮人处理过很多次绝大多数不是系统损坏而是下面几个原因之一。按照先本地后远程、先索引后仓库的顺序排查# 第一步更新源索引 sudo apt update # 第二步如果更新时报错看具体错误来源 # 常见是源地址失效、网络不通、GPG 签名错误 tail -n 30 /var/log/apt/apt.log # 第三步确认源的 URL 可访问 curl -I http://mirrors.aliyun.com/ubuntu/dists/jammy/Release # 第四步确认包名确实存在 apt search 你要装的包名如果源配置没问题、包名也没拼错依然报Unable to locate package还有一个容易被忽略的场景某个包只在特定组件里有比如ubuntu-restricted-extras在multiverse组件下你的sources.list里没启用这个组件。修改源文件加上 multiverse再 update 一下就能解决。5.2 服务进程突然消失以 mysqld 进程为例的日志排查法服务器上跑的 MySQL 进程突然没了很多人的第一反应是 raw 数据损坏或被黑。实际上先别慌从这几个角度排查# 第一步看系统日志里有没有内核级终止记录 sudo journalctl -u mysqld --since 10 minutes ago # 第二步查 MySQL 错误日志 sudo tail -n 100 /var/log/mysql/error.log # 第三步看有没有 OOM内存不足的记录 sudo dmesg | grep -i oom完全有理由先检查 OOM。Linux 有一个机制叫 OOM Killer当系统内存耗尽时内核会挑一个进程杀掉以回收内存而且专挑占用内存大、评分高的进程下手。如果你看到 dmesg 输出里有Out of memory: Kill process xxx (mysqld)那问题根因就不是MySQL 为什么挂了而是什么把内存吃完导致 MySQL 成了牺牲品。排查内存大户ps aux --sort-%mem | head -20这个案例想表达的是进程消失往往只是果真正的因在其他地方。养成看日志、看内核信息、看资源的顺序习惯比急着重启服务有用得多。5.3 实战案例Java 应用 CPU 飙高如何定位到具体线程线上 Java 应用 CPU 持续 100%用top看到 java 进程占满 CPU怎么定位三步走是我常用的# 第一步找到 java 进程 PID top -c -p $(pgrep -f application.jar | head -1) # 第二步把进程内所有线程按 CPU 占用排序找到飙高的线程 TID top -H -p 1234 # 第三步把线程 ID 转十六进制 printf %x\n 12345 # 然后使用 jstack 导出线程堆栈搜索该线程 TID jstack 1234 /tmp/stack.log grep -A 30 0x3039 /tmp/stack.logtop -H查看的是线程级别单个线程的 CPU 占用出来以后转十六进制去jstack堆栈里找对应线程名和堆栈信息。绝大多数情况下看到的会是一个业务线程卡在某个方法上比如等待数据库连接、死循环、GC 停顿或者锁竞争。有了堆栈这第一手材料才能对症下药。逻辑强相关的是热搜词里进程堆大小调整报错 java.lang.OutOfMemoryError这类问题我也会顺手看jvm的-Xmx参数和Heap占用确认是不是堆太小导致的连环 GC。6. 几个可以明显提升效率的小习惯6.1 用 pgrep 和 pkill 代替 grep ps 组合我见过不少人在脚本里写ps aux | grep nginx | grep -v grep | awk {print $2}太绕了。pgrep本身就是为了按进程名查找 PID 设计的pgrep -f nginx # 按命令行匹配返回 PID pgrep -u www-data # 按用户匹配脚本里判断某个服务是否在运行if pgrep -x nginx /dev/null; then echo nginx is running else echo nginx is not running fi-x表示精确匹配进程名能避免把自己这个 pgrep 命令本身匹配进去。写脚本判断非常简单而且不用处理 awk。6.2 at 和 systemd timer需要定时任务时不只有 croncron是不是唯一选择不是。临时性的任务、只在某个指定时刻干一次的任务用at更合适sudo apt install at echo sudo systemctl restart nginx | at 02:30定期任务除 cron 以外现在更推荐 systemd timer。用 systemd timer 的好处是可以把定时逻辑与服务的配置统一管理能查看日志也能处理依赖关系。虽然这算进阶内容但既然你已经理解 systemd 管理进程把 cron 换成 timer 只是换一个思路罢了。6.3 排查进程时先看时间线再看资源线最后总结一个排查习惯进程出问题不要急着杀要沿着时间线重建现场。先问自己几个问题——这个进程什么时候开始异常的当时系统有没有做过升级、改过配置、跑过批量任务再去看资源线——CPU、内存、IO、网络四类资源哪一条先出现异常举一个我真实的经历某次线上服务响应变慢我看进程占用不高CPU 正常内存正常但磁盘 IO 持续高位。最后查下来是隔壁部门半夜跑了个数据同步任务把磁盘带宽吃满了整个机器的应用全部变慢。如果只盯着进程看永远找不到根因。所以进程管理和软件包管理表面上都是命令问题实际上都要求你建立系统是一个整体的思维模型。软件包装不上可能是源、网络、架构、依赖的任意一环进程跑不动可能是资源、代码、配置、底座的任意一环。命令只是工具能顺着线索把问题的链路连起来才是管理 Linux 的核心能力。
返回列表