第一次在Linux服务器上排查磁盘告警时,我盯着根目录那一串名字看了十几分钟。df显示/已经用到97%,但du下去全是又碎又多的小文件,根本分不清哪些能删、哪些不能删。这种场景,凡是摸过Linux的人应该都不陌生。说白了,问题不在“记不记得目录名”,而在有没有建立起对Linux根文件系统各文件夹作用的整体认知。很多人会背/bin、/usr、/var,但真到排障时,不知道日志在哪个目录、不知道/usr/local和/usr/bin的区别、不知道/var/tmp和/tmp为什么同时存在,最后只能靠百度一条条搜。
这篇博文打算做一次系统性梳理。我会把整个根目录按“启动、运行、数据、设备、挂载”几个角色拆开,每个目录讲清楚设计意图、实际用途和排障时怎么用。适合刚接触Linux、想建立目录认知的同学,也适合已经工作两三年、对目录眼熟但说不出所以然的开发或运维。把这些吃透之后你会发现,Linux排障很多时候就是“按图索骥”——你知道证据放在哪个目录,问题就解决了一半。
1. 先建立一个全局认知:根目录不是“放文件的根目录”,它是一张城市功能分区图
1.1 挂载点思维:为什么说根目录是一棵树的根
Linux根文件系统(也就是/)不只是“放文件的地方”,它更像一棵目录树的起点。所有磁盘、分区、网络存储,最终都要通过挂载的方式接到这棵树的某个节点上。这和Windows的盘符逻辑完全不同——Windows的C盘、D盘、E盘是并列关系,而Linux没有“盘符”概念,第二块硬盘插进来之后,你得决定把它挂到哪个目录下。
举个例子,假设机器有两块盘,/dev/sda1挂载到/,/dev/sdb1挂载到/home。那么你在/home下看到的所有内容,其实都来自第二块盘,而不是根分区。很多人第一次用df -h时很惊讶:明明根分区快满了,为什么/home下面还能写那么多东西?因为它根本不在根分区里。这就说明,目录的“身份”会随挂载方式改变,排查磁盘问题时最好先用lsblk和df -h对比着看,确认哪个目录到底落在哪块盘上。
另外,系统启动早期只有/这个根文件系统,/usr、/home等目录如果不在根分区上,启动过程中需要先挂载它们才能继续。这也是为什么/bin、/lib这类基础目录必须设计在根文件系统内部的原因——启动早期没有任何额外依赖,如果连最基本的命令都找不到,系统根本起不来。
1.2 目录不是乱建的,它们遵循一套分类协议
Linux目录结构并非拍脑袋定出来的,而是有一份叫做FHS(文件系统层次结构标准)的规范在约束。简单说,FHS就是一份“城市分区规划”,明确规定/user/bin该放什么、/var/log该放什么、/tmp该放什么。虽然不同发行版会有细微差异,但大的分类框架几乎一致。这也是为什么你从CentOS切到Ubuntu、从Debian切到Arch,目录的大致结构依然能一眼看懂。
我把顶层目录按角色归了一下类,后面几个大章节就是按这个分类展开的:
| 目录 | 一句话定位 | 我的常用场景 |
|---|---|---|
| /bin | 基础用户命令 | 系统启动和救援模式下的ls、bash等 |
| /sbin | 系统管理命令 | 分区、格式化、重启等管理员操作 |
| /lib | 共享库与内核模块 | 程序运行依赖的.so和驱动模块 |
| /usr | 系统主要程序与资源 | 绝大多数软件的安装位置 |
| /etc | 系统全局配置 | 修改服务端口、开机挂载项 |
| /var | 可变化的数据 | 日志、缓存、运行时数据 |
| /dev | 设备文件 | 磁盘、终端、输入输出设备节点 |
| /proc | 进程与内核实时信息 | 查看内存、CPU、进程参数 |
| /sys | 设备与驱动模型视图 | 查看硬件属性和可调参数 |
| /tmp | 临时目录 | 程序运行时的临时文件 |
| /home | 普通用户家目录 | 存放个人文件与配置 |
| /root | 管理员家目录 | root用户的专属空间 |
| /mnt | 临时手动挂载点 | 手动挂载磁盘或ISO文件 |
| /media | 可移动设备自动挂载 | 插入U盘、移动硬盘后自动出现 |
| /run | 运行时数据,内存盘 | PID文件、socket文件 |
| /opt | 第三方商业软件 | 带独立目录的闭源软件 |
| /srv | 本机服务数据 | 网站、FTP等服务的数据文件 |
| /lost+found | 文件系统恢复区 | 断电或异常后找回的碎片文件 |
注意一下/run,很多新手会忽略它。/run是一个基于内存的临时文件系统,重启就清空,里面放的是各种服务的PID文件和socket文件。你在/var/run看到的东西,其实是一个指向/run的软链。看到/run下面一堆小文件不用慌,那是正常的运行时状态。
先建立这个“分类思维”之后,后面每个目录的具体作用就会很好理解。遇到陌生目录,先问自己一句:它属于哪一类?是启动基础设施,还是程序资源,还是动态数据,还是设备视图?这个问题一旦能答上来,目录的作用基本就猜得八九不离十了。
2. /bin、/sbin、/lib:系统启动阶段的基础设施,也是现代系统里“名存实亡”的三个目录
2.1 传统分工与今天的软链合并
如果你在较老的Linux教科书上会看到这样的解释:/bin存放基本用户命令、/sbin存放系统管理命令、/lib存放系统运行需要的共享库。这个分工本身没错,它是早期设计者为了让系统在启动早期也能正常工作而做的规划。早期根文件系统空间很小,而/usr可能是一个独立分区,系统启动时要先把根分区挂载好、跑起最基本的命令,才能去挂载/usr。所以/bin、/sbin、/lib必须独立于/usr存在。
但现代发行版基本都做了usr合并。你在新系统上执行ls -l /bin,大概率会看到/bin -> usr/bin这样的软链;/sbin和/lib同样是指向/usr下对应目录的软链。这并不奇怪,因为现在大部分安装场景根分区和/usr分区已经不再分离,继续维护两个平行的命令目录反而增加管理成本。
我在新环境里习惯先执行readlink -f /bin确认一下,返回/usr/bin就说明这套系统已经完成了目录合并。在救援模式或者进入live系统后,这个判断特别有用——你能快速搞明白自己面对的是一个传统目录结构的系统,还是现代合并结构的系统,后续修复路径完全不同。
2.2 /bin里到底有哪些“命根子”命令
/bin在传统意义上放着系统最基本、最核心的命令:bash、sh、ls、cat、mv、rm、cp、mkdir、grep、sed、awk、tar等。为什么这些命令必须放在系统启动早期就能访问的地方?因为一旦系统出现故障进入单用户模式或救援模式,你能用的就是这一小撮命令。没有bash,你连修复脚本都跑不了;没有mount,你连其他分区都挂不上。
我见过有同事为了清理磁盘空间,把/bin下“看起来没用”的静态二进制文件删掉,结果系统重启后直接进不了正常模式。也就是说,这些目录里的东西不能靠“感觉”去清理,每一个都可能被系统启动链路依赖。真到救援模式之后,如果你想用包管理器重新安装被误删的包,chroot进原系统、挂载/dev和/proc、再重新安装对应软件包,也是个烦琐的流程,能避免就别走到那一步。
2.3 /sbin与/lib的细节问题
/sbin传统上放系统管理和启动相关的命令,典型的有fdisk、mkfs、fsck、reboot、shutdown、systemctl等。普通用户的PATH里通常不包含/sbin,所以我在排查问题时经常需要输入完整路径,例如/sbin/fsck。由于usr合并,这些命令的实际文件通常在/usr/sbin里,/sbin只是入口。
/lib值得多说两句。这里存放两类东西:一类是共享库(.so文件),程序运行时动态链接的依赖;另一类是内核模块,路径一般是/lib/modules/内核版本号/。我遇到过一台机器升级内核后网卡驱动加载不了,排查时第一反应就是去/lib/modules/$(uname -r)下看驱动文件在不在。如果模块缺失,很多外设会变得不可用,而且开机报错不一定明显。另外,可以用ldd $(which ls)查看ls命令依赖了哪些库,如果在系统里看到一堆程序报“error while loading shared libraries”,基本都是/lib或者/usr/lib下的库文件出了问题。
给新手一个建议:/bin、/sbin、/lib这三个目录,默认不要去动文件,哪怕你认为某个文件“没用”。它们属于系统基础设施,安全边际极低,误删的代价远比省下的那点空间大。
3. /usr:真正的大本营,平时跑的绝大部分程序都在这里
3.1 名字的误会:它不是“用户目录”
很多人看到/usr就以为是user的缩写,觉得它应该用来存放用户文件,其实这完全是个误会。/usr的完整含义更接近UNIX System Resources,也就是Unix系统资源目录。你登录系统之后输入的大多数命令,实际文件都在/usr/bin下;系统管理命令在/usr/sbin;共享库在/usr/lib。我自己新装系统后第一件事就是看一眼/usr目录有多大,因为它基本等于Windows里的Program Files加System32,内容量通常比根目录其他区域都大。
在/usr这个目录下,还有一个容易被忽视的点:/usr/share。它存放与CPU架构无关的共享数据,例如man文档、图标、locale语言包、时区库、一些程序自带的模板文件。有些程序改了/usr/share下的默认配置再升级就会被覆盖,所以自定义配置一般不建议放在/usr/share,而应该放到/etc对应位置。
3.2 /usr/local与系统包管理的边界
/usr目录下最重要的分区之一就是/usr/local。这个目录专门预留给管理员手动编译安装的软件。用源码装软件时,经典三步是./configure --prefix=/usr/local,然后make,最后make install。装完之后,可执行文件通常落在/usr/local/bin,库文件落在/usr/local/lib,配置文件落在/usr/local/etc。
为什么要单独搞一个/usr/local,而不是直接装到/usr里?核心原因是职责分离。系统包管理器(apt/yum/dnf等)安装的文件归包管理器管,卸载升级很方便;而你自己编译的软件放/usr/local,相当于一个“手动管理区”,不容易和系统包管理器相互干扰。大多数系统PATH里/usr/local/bin排在/usr/bin前面,所以你源码编译安装的新版本nginx,会优先于系统自带的旧版本被调用。
这里有个实操细节:手动编译安装的库,如果忘记刷新动态链接库缓存,运行程序时会报找不到libxxx.so。解决办法是在/etc/ld.so.conf.d/下新建一个配置,把/usr/local/lib写进去,然后执行ldconfig,让系统找到这些新库。这个坑我在迁移旧服务时踩过好几次,每次都是“程序装了但起不来”,原因就是这个。
顺带说下/opt。它一般给第三方闭源商业软件用,每个软件一个独立子目录,比如/opt/xxx/bin、/opt/xxx/lib。卸载时直接删掉整个软件目录、再清理一下PATH里的软链即可,干净利落。
3.3 /usr/lib与/usr/libexec:默认程序与内部可执行文件
/usr/lib在usr合并之后,承接了传统/lib的大部分职责,存放各种共享库。另外,/usr/lib/systemd/system这个路径很值得认识——它是系统自带systemd服务单元的默认存放处。很多服务软件安装时会在这里扔一个.service文件。
但自定义服务千万不要直接改/usr/lib/systemd/system里的内容。这个目录由软件包管理,升级时会被覆盖。正确的做法是把要修改的unit文件复制到/etc/systemd/system,再在那边改。这是Linux系统里一个非常典型的“默认与覆盖”设计:/usr/lib里的东西是“软件出厂默认”,/etc里的东西是“本地管理覆盖”。理解了这个逻辑,你对/etc、/usr、/var三者的分工也就基本通了。
4. /etc、/var:静态配置与动态数据的“双人舞”,也是最常出问题的两个目录
4.1 /etc:机器自己的设置中心
/etc存放的是系统全局配置文件,特点是“静态”,也就是不经常变化。不像/var下那些日志和缓存会一直增长,/etc里的内容更多是你在安装软件、修改端口、调整开机项时才会动到。常见的像/etc/passwd、/etc/shadow(用户账号信息)、/etc/hosts(主机名解析)、/etc/resolv.conf(DNS配置)、/etc/ssh/sshd_config(SSH服务配置)、/etc/fstab(开机挂载表)都在这里。
修改/etc配置时,我强烈建议你先备份再动手。一条简单命令就能做到:cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%F)。改完之后重启对应服务验证,确认没问题再继续。很多人直接改、直接重启、然后发现服务起不来,想回滚发现原文件已经被覆盖了,这种教训实在太多。
还有一个容易被忽视的点:/etc下有些文件其实是软链。典型的是/etc/localtime,它通常指向系统时区库里的某个时区文件。看到软链不要惊讶,这是系统管理时区的正常套路。另外,/etc/profile.d和/etc/default是两个很有用的补充目录,前者存放登录环境变量脚本,后者存放一些服务的默认启动参数。有些自定义环境变量写到/etc/profile.d/下比直接改/etc/profile更清晰,因为每个软件一个独立文件,好管理也好排查。
4.2 /var:会动的数据都在这里
/var是系统里“动数据”的大本营,几乎一切会增长、会变化的数据都在这个目录下。它名字来自variable,可变的意思。排障时我最先看的永远是/var/log,那是系统日志和应用程序日志的核心位置。传统Linux下常见的日志文件包括/var/log/messages、/var/log/syslog、/var/log/auth.log、/var/log/kern.log,不同发行版文件名略有差别。用了systemd日志的系统上,很多传统日志文件不再实时更新,要用journalctl查看,这点需要适应。
/var/lib存放各种服务程序的运行时数据。数据库的数据文件一般在这里,例如/var/lib/mysql、/var/lib/postgresql;容器引擎的数据也在/var/lib/docker下。做磁盘空间排查时,/var/lib往往是最大头。
/var/cache放缓存文件,最典型的是软件包管理器的缓存目录,例如/var/cache/apt/archives下的deb安装包。这类缓存清理掉通常不影响系统运行,只是下次安装时可能重新下载。
/var/tmp也是一个临时目录,但它和/tmp有本质区别:/tmp的生命周期很短,重启后基本清空;/var/tmp的生命周期长,一般能保存数天甚至更久,适合放“比会话稍长、但又算不上正式数据”的临时文件。我在需要临时保存一个大文件、又担心重启会丢的场合,都会丢到/var/tmp而不是/tmp。
/var/spool也很容易被忽略,它存放排队处理的业务数据,比如打印队列、邮件队列。某些发行版的计划任务文件也在这里,例如/var/spool/cron。清理/var时如果不了解这些目录的作用,很容易误删关键数据。
4.3 日志清理的正确姿势
日志目录长了之后,磁盘空间告急是最常见的事故。我处理过的服务器故障里,相当大比例都是日志爆盘。检查日志占用可以用journalctl --disk-usage,如果journal日志太大,执行journalctl --vacuum-size=200M就能把日志压缩清理到200M以内,非常安全。
传统文本日志(比如/var/log/nginx/access.log)不要直接rm -rf。很多日志文件正在被进程写入,直接删掉后句柄还占着,磁盘空间不会立即释放,而且新日志也写不进去,界面看起来就是“文件没了但空间没回来”。正确做法是用truncate -s 0将日志文件长度清零,日志进程依然持有合法句柄,空间立即回收。这在线上环境处理紧急磁盘故障时是常规操作。
4.4 配置与数据的一对“最佳实践”
把/etc和/var放在一起看,其实是一套很清晰的策略:程序默认配置放/usr/lib,系统级配置放/etc,运行数据放/var/lib,日志放/var/log,缓存放/var/cache。这样划分之后,备份系统时你只要重点保护/etc和/var/lib;监控磁盘时重点盯/var;重装系统时/usr可以被轻易替换,但/etc和/var里的数据要保留。这套逻辑想通了,很多“为什么要单独分一个/var分区”的问题也迎刃而解。
5. /dev、/proc、/sys:三个特殊文件系统,从抽象设备到内核运行时视图
5.1 设备文件的真相:/dev不是普通目录
Linux哲学里有一个“一切皆文件”的说法,/dev就是这个哲学的实体化体现。机器上的硬盘、终端、串口、音频设备,都会在/dev下体现为设备节点文件。但注意,这些文件并不是真的在磁盘上,而是由一个叫devtmpfs的虚拟文件系统在内存中创建的。
用ls -l /dev/sda看,文件类型的第一个字符是b(块设备),而/dev/tty之类的字符设备是c(字符设备)。块设备意味着数据可以按块随机读写,典型的就是磁盘;字符设备则是按字符流读写,典型的是终端。理解了这个区别,你在看设备文件时就不会一脸茫然。
现代系统里,设备节点基本由udev负责创建和命名。你插入一个U盘,udev会根据内核上报的信息自动生成/dev/sdb1之类的节点,不需要手工mknod。所以如果你发现/dev下少了某个设备节点,大概率是udev规则问题,而不是系统丢了文件。
实际工作中我更推荐用/dev/disk/by-uuid或/dev/disk/by-id这样的路径来引用磁盘,因为直接使用/dev/sda、/dev/sdb这样的名称,设备顺序在重启后可能变化,容易导致挂载错盘。fstab里能用UUID就尽量用UUID,这是减少宕机事故的一条重要经验。
5.2 /proc:进程与内核的即时窗口
/proc是一个典型的伪文件系统,里面没有真实文件,所有内容都是内核运行时的数据,每次读取时动态生成。你可以把/proc理解成一扇面向内核和进程的实时窗口。
最常用的几个:/proc/cpuinfo看CPU信息,/proc/meminfo看内存信息,/proc/partitions看分区信息,还有/proc/net/dev看网络接口流量统计。每个运行的进程都会在/proc下有一个以进程号命名的目录,里面放着cmdline、environ、fd、status等进程元数据。要查看某个进程的命令行参数、打开哪些文件、当前运行状态,都可以进去找。
特别提一下/proc/sys,它是内核参数的直接入口。常见的网络转发开关net.ipv4.ip_forward、TCP连接复用开关tcp_tw_reuse都在这里。直接echo修改会立即生效,但重启就失效。如果你想持久化,就应该写成/etc/sysctl.conf里的配置,再执行sysctl -p。这种方式比直接echo安全得多,也方便审计。
5.3 /sys:设备与驱动模型的属性面板
/sys目录比/proc更“结构化”,它把设备、驱动、总线之间的关系组织成了一棵可视的树。/sys/class/net下能看到每个网络接口,/sys/block下能看到每个块设备,/sys/bus/pci下能看到PCI总线上挂的设备。想确认网卡队列数、磁盘调度器、电源管理状态,去/sys下面找对应目录基本都能找到。
/sys里很多属性是可写的,但写错了可能直接影响硬件状态。我在调试虚拟机时曾经调整过/sys/class/backlight下的背光亮度值,写错直接黑屏。所以对/sys下手前一定要确认写入的值和格式,最好先去文档里查清楚。
5.4 特殊文件系统的共性与常见误解
很多人第一次在/proc/sys或/sys下看到文件大小都是0,会以为内容为空。这是伪文件系统的特征——文件大小不代表内容长度,数据是读取时实时生成的。你想保存/proc里的某个状态,千万别用cp,直接cat /proc/meminfo > /tmp/meminfo.txt,把内容重定向到普通文件里保存。也不要想着用vi直接编辑/proc和/sys下的文件,格式稍有不对就是报错或异常。凡是涉及系统参数的改动,优先用sysctl和系统提供的专用工具,不让应用层直接写内核伪文件。
6. /tmp、/home、/root、/mnt、/media:日常工作区的划分与挂载点管理
6.1 /tmp和/var/tmp的临时区规则
/tmp是所有用户都能用的临时目录,可能也是新手第一次接触到“权限位121”概念的地方。执行ls -ld /tmp会看到drwxrwxrwt,末尾的t就是sticky bit(粘滞位)。它的作用是:所有用户都可以在这个目录下创建文件,但只有文件所有者和root才有权删除别人的文件。这个设计非常实用,否则A用户创建的临时文件可能会被B用户随手删掉。
修改临时目录权限时要特别小心。如果/tmp被chmod改成777,就丢掉了粘滞位,用户之间就可以互相删除临时文件,安全隐患很大。/var/tmp虽然也叫临时目录,但因为长期保存,反而更容易被塞进大文件。清理时养成习惯:先看目录占用,再决定清什么。
6.2 /home、/root与用户隔离
/home是普通用户家目录的集合,像/home/zhang、/home/li。这里存放每个用户自己的文档、代码、个人配置。服务进程也经常以专用用户运行,它们没有普通家目录,数据直接放在/var/lib下。所以看到某台机器上没有某个用户的/home目录,不代表这个用户不存在。
需要注意权限控制。家目录默认通常比较保守,但如果被改成755,其他用户就能进入你的目录读取文件。SSH相关的.ssh目录权限必须足够严格,一般要求700,authorized_keys要求600,否则SSH为了安全会直接拒绝加载密钥。我见过不止一次因为权限太松导致密钥登录失败的案例,调试半天才发现是权限问题。
/root是root管理员的家目录,普通用户没有权限进入。但需要注意,单用户模式或救援模式下你就在root环境里,/root下的脚本、备份、历史命令记录都可能成为排障线索。
6.3 挂载点的管理哲学
/mnt和/media是两个历史悠久的挂载点目录。传统上/media用于可移动介质(U盘、光盘)的自动挂载,/mnt用于管理员手动挂载临时文件系统。现代桌面环境插入U盘后会出现在/media或/run/media下,而服务器场景下/mnt则经常被用来挂载临时磁盘、ISO镜像或网络存储。
其实挂载点目录本身没有硬性限制,完全可以用/data、/backup这类自定义路径。但有一个坑必须提醒:挂载点目录必须是存在的空目录。你把新磁盘挂载到某个目录上,如果该目录原本有数据,挂载后这些数据会被“隐藏”掉——它们还在磁盘上,但从这个目录看不到了。新手遇到这种情况往往会以为数据丢了,其实只要umount挂载点,原始内容就回来了。所以挂载之前我习惯先ls一下目标目录,确认它是空的,或者先把原始数据挪走。
6.4 /srv、/opt、/lost+found:三张冷门卡
/srv、/opt、/lost+found平时用得不多,但看到时要知道它们是干嘛的。/srv用于存放本机对外提供服务的数据,有些发行版的Web站点根目录会放在/var/www,有些则放在/srv/www,这属于发行版习惯差异,不违反FHS精神。没有用到时不需要刻意创建,目录是“用到才存在”的。
/opt前面已经提过,是第三方闭源软件的窝。删除软件时直接删整个目录就行,但注意先确认PATH里的软链指向,不然会出现软件删了但命令还在PATH里的情况。
/lost+found是ext系列文件系统在异常断电或者文件系统损坏后,由fsck找回的碎片文件安置处。它不是垃圾箱,也不能随手清空。看到里面有文件,要先判断是哪些目录下丢了数据,能恢复则恢复,不能也要先保留现场。
7. 实战向的三个排查场景:目录不见了、空间满了、系统起不来
7.1 磁盘空间满:先看/var,再查删除进程
处理磁盘告警我一般按固定顺序来:先df -h看整体水位,再du -sh /*看根目录下哪个一级目录最肥,然后顺着du -sh /var/*逐层往下钻。这套组合拳打下来,大头基本能揪出来。如果日志系统用systemd,优先执行journalctl --disk-usage和journalctl --vacuum-size=200M回收空间,这个操作对系统几乎零风险。
如果du显示文件总大小不大,但df显示磁盘占用很高,十有八九是文件被删除了但进程还占着文件描述符。这时候用lsof | grep deleted找出那些“幽灵文件”,定位到对应进程,重启服务或让进程重新打开文件,空间才会真正释放。我处理过一台Nginx服务器,access.log被误删后磁盘空间依然满着,原因就是worker进程还握着那个被删除文件的句柄。
另外提示一句,df -h看的是空间,df -i看的是inode。如果inode耗尽,磁盘明明有空余,却依然无法创建任何新文件,这种问题在存放大量小文件的目录(比如/var/spool或邮件目录)里很常见。排查时两个维度一起看,别只盯空间。
7.2 不该删的目录被误删:现场怎么抢救
误删目录后,第一原则是立刻停止对该分区的一切写入操作,有条件的先做镜像备份,避免后续操作覆盖掉待恢复的数据。然后进入救援模式或者live系统,用chroot把原系统的根分区切进去,再用包管理器的reinstall能力重新安装被影响的包。
比如误删了/lib/modules导致网卡驱动丢失,可以chroot后重新安装对应内核包或驱动包;误删了/usr/share导致软件找不到数据文件,就重新安装相关软件包。仓库里有的文件都能通过包管理器找回。不要手动从另一台相同系统的机器上直接scp文件覆盖,尤其是库文件和符号链接,版本稍有出入会让问题越来越复杂。如果数据目录被删,比如/var/lib/mysql,包管理器也救不回来,这时候只能靠备份。这也是为什么我一直强调,/var/lib这种动态数据区必须纳入备份策略,光重装软件没有意义。
7.3 开机停在维护模式:大多数时候是/etc/fstab挂载项出问题
开机直接进入emergency mode或maintenance mode,提示需要root密码或journalctl查看日志,这类故障我遇到最多就是/etc/fstab写错。典型原因包括UUID改了、设备名变了、挂载参数失效。系统启动时有一个分区挂载失败,就会放弃继续启动。
处理流程不复杂:先看屏幕提示里的设备或UUID,再执行journalctl -xb查看启动错误日志,确认是哪个挂载项失败。如果确实写错了,用mount -o remount,rw /把根分区重新以可写方式挂载,然后编辑/etc/fstab把错误行注释掉,或者改成正确的UUID。改完后执行mount -a验证所有挂载项都能正常通过,再重启测试。
预防这个问题的成本极低:改/etc/fstab之前先备份,cp /etc/fstab /etc/fstab.bak,这是我在所有生产机器上的固定习惯。fstab里尽量用UUID而不是/dev/sdX,因为设备名会漂移。
8. 最后一组心得:目录理解到位,排障效率才会真的上来
写到这里,想分享几条我自己用下来的心得。第一,认识Linux目录不是背单词,核心是建立“哪个角色放在哪”的思维模型。遇到一个陌生目录,先判断它属于启动、程序、配置、动态数据、设备还是挂载点,分类对了,下一步该看哪里基本就清楚了。
第二,我维护机器有个固定动作:改配置前先备份,处理容量问题先看/var和inode,新环境一定用lsblk确认挂载结构。这套流程看着简单,实际上能避开绝大多数低级事故。有一次我从一个同事手里接一台老机器,对方说“根分区频繁满”,我上去第一件事就是看挂载表,发现/var给了独立分区但日志没做轮转,问题根源一眼就找到了。
第三,如果记不住整套目录约定,man hier一页文档就能快速过一遍完整规则。新到手一台不熟悉的机器,tree -L 1 /扫一眼顶层结构,心里就有谱了。真正干活的时候,lsof看文件占用、ldd看程序依赖、df和du配合找空间大户,基本覆盖了日常90%的排查需求。
把这些目录当成一张城市地图带着走,遇到系统问题你就是在不同街区里找线索:日志异常去/var/log,配置错误去/etc,程序缺失去/usr,设备异常去/dev和/sys,启动异常回根目录查挂载关系。地图越熟,排障越快,这就是理解Linux根文件系统各文件夹作用最实在的回报。