前两天帮人处理一台云电脑重装的事,对方一脸懵:“我的数据盘是配好了的,重装前要不要做什么操作?”我一听就明白,这背后缺的正好是用户管理和系统管理这两块最基础、又最容易被忽略的知识。上服务器排查时更明显,账号权限乱、进程没人管、日志不会查、定时任务写错了没人发现——平时看着都是小事,真正出问题时全是坑。
这篇文章我想把这些年攒下来的用户管理与系统管理实战经验整理出来,从账号体系、进程信号、性能监控、定时任务,再到日志排查和 LVM 存储,适合自己维护服务器或云电脑的人,也适合准备信息系统管理工程师这类考试的朋友当作实操复习材料。内容尽量说人话,命令都贴实际的,你照着敲基本不会翻车。
1. 用户管理链路:从账号文件到 sudo 授权的完整认知
1.1 用户和组:不是“账号密码”那么简单
很多人对用户管理的理解停留在 adduser、passwd 这种操作上,但真正干活的时候会发现,权限问题、文件归属问题、服务启动身份问题,全都和“用户与组的关系”挂钩。
Linux 里一切资源的识别不是靠用户名,而是靠 UID。用户名是给人看的,UID 才是内核认的数字。组也一样,一个用户必须有一个主组,同时可以加入多个附加组。理解这个结构有什么用?举一个最常见的场景:Nginx 是 nginx 用户启动的,MySQL 是 mysql 用户启动的,那 nginx 想去读 mysql 目录下的文件时,能不能读得到?这取决于目录的属主属组和权限位。如果你想让 nginx 能读到 mysql 的日志目录,最简单的做法就是把 nginx 用户加进 mysql 组,而不是把目录改成 777 或者把整个权限放开。这就是用户管理的日常用法。
1.2 账号文件:每一行字段都是有意义的
我排查账号异常时,第一件事一定是看这几个文件:
- /etc/passwd 存账号基本信息
- /etc/shadow 存密码哈希和过期策略
- /etc/group 存组信息
/etc/passwd 里每一行是冒号分隔的七个字段:用户名、密码占位符(一般是 x)、UID、GID、注释信息、家目录、登录 Shell。宁可漏看一条日志,也不能不看 UID,因为系统判断权限只看数字。如果你手抖把两个账号的 UID 改成一样的,那这两个账号在文件权限上就完全等价了,这是个很容易被忽视的雷。
/etc/shadow 里的字段更关键:密码哈希、最近修改时间、最短修改天数、最长有效期、过期警告天数、宽限期。很多安全基线要求密码 90 天改一次,如果你不想装额外工具,直接在 shadow 文件里调整第五六个字段,或者用 chage 命令操作。给个实际例子:
bash复制chage -M 90 zhangsan
这条命令设置 zhangsan 的密码最长有效期为 90 天。chage 还有一个特别实用的参数 -d,可以强制用户下一次登录时改密码,这是给新员工开账号时常用的手法。
1.3 权限位:rwx、粘滞位和 ACL
权限这块,我的核心建议是:能用组解决的事不要用 777 解决,能不用 root 就不用 root。普通权限只能用三个维度表达:属主、属组、其他人。这在多目录、多角色的真实业务里是不够用的,所以有 ACL(访问控制列表)。
举个例子,团队里有运维组和一个数据分析临时项目组,有个目录需要给新项目组只读权限,但不想改变目录现有属主属组。这时候用 setfacl 比改属组干净得多:
bash复制setfacl -m u:analyst_group:r-x /data/project
getfacl /data/project
setfacl 追加一条对应组的读执行权限,getfacl 能看到生效的 ACL 列表。另外还有三个特殊权限位值得留心:setuid、setgid、粘滞位。setuid 出现在可执行文件上时,会让运行该文件的进程拥有文件属主的权限,比如 /usr/bin/passwd 就带了 setuid 位,所以普通用户才能去修改 /etc/shadow 里的密码字段。粘滞位一般在 /tmp 这种公共目录上,保证用户只能删自己的文件,不能顺手删别人的。
1.4 sudo:最小授权原则怎么落地
管理多台服务器时,我碰到最多的问题就是大家都在用 root 干活,出了事根本分不清是谁干的。所以生产环境一定收敛 root 登录,改用 sudo 最小授权。
第一步让 admin 用户能执行全部管理命令并输入密码确认:
code复制admin ALL=(ALL:ALL) ALL
第二个 ALL 表示可以切换成任意用户执行命令。这句配置有风险,因为 admin 可以 sudo su - 变成 root,从审计角度讲和直接给 root 没区别。更严格的做法,是只给特定命令授权,比如:
code复制deploy ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl reload nginx
这样 deploy 用户只能重启和重载 Nginx,做不了其他管理操作。修改 sudo 配置一定要用 visudo,不要直接编辑 /etc/sudoers,语法错误会导致整个 sudo 瘫痪。
我还习惯在 sudoers 里保留 secure_path 这个默认项,它决定 sudo 执行时用哪套 PATH 环境变量。很多诡异的问题,比如明明装了命令但 sudo 提示 command not found,多半就是 PATH 不含该命令所在目录,而 secure_path 把 PATH 限制死了。排查这个,先坚持用 pkill 或者哪条命令绝对路径跑通,再看环境变量。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 进程与后台任务:从 kill 信号到 systemd 的正确理解
2.1 进程查看:ps 和 top 分别解决什么问题
排查系统卡顿、服务挂掉、端口占用,第一步都是看进程。ps 适合抓快照,top 适合盯动态变化。
bash复制ps aux --sort=-%cpu | head -20
这是我查高 CPU 进程最快的方法,按 CPU 降序排前 20 个。ps -ef 看进程树和父子关系更方便,比如发现一个进程怎么都杀不死,往往是它的父进程还活着会不断拉起新实例,这时候要往上看一眼 PPID。
top 进去以后有几个键务必记住:P 按 CPU 排序,M 按内存排序,1 查看每个逻辑核的使用情况。光看整个系统的 CPU 平均使用率经常会漏事,四核机器里有三个核空转,一个核 100%,平均下来只有 25%,如果没按核看,根本找不到热点线程。
2.2 信号机制:为什么 kill -9 不是首选
进程后台管理绕不开信号(signal),我见过太多人一卡就喜欢 kill -9,其实信号是有阶层的。常用信号整理一下:
| 信号 | 数值 | 触发方式 | 默认效果 | 使用场景 |
|---|---|---|---|---|
| SIGINT | 2 | Ctrl+C | 中断进程 | 交互式前台任务终止 |
| SIGHUP | 1 | 断开终端 | 挂断终止 | 配置变更后重读配置 |
| SIGTERM | 15 | kill 默认 | 正常退出 | 优雅停止业务进程 |
| SIGKILL | 9 | kill -9 | 强制杀死 | 处理完全无响应的进程 |
SIGTERM 是请进程“收拾一下再走”,进程可以自己捕捉这个信号做清理动作,比如释放锁、保存状态、断数据库连接。SIGKILL 则是内核直接接手,进程没有任何机会做收尾,可能留下临时文件、半写状态的数据。所以我处理服务时,默认先打 SIGTERM,观察几秒没动静再考虑 SIGKILL。
还有几个信号有特殊用法。nginx -s reload 走的是重新打开配置并平滑重载,靠的就是 SIGHUP 类机制。如果你调试一个长期后台任务,希望它退出时自动让父终端得知,可以 kill -1 把它挂的回话断开。总之,信号记不住所有数字没关系,记住 SIGTERM 和 SIGKILL 两档就够了。
2.3 后台任务的正确姿势:nohup、& 和 tmux
在服务器上跑长任务,比如导数据、跑全量备份,如果直接开一个 SSH 窗口执行,一关终端任务就没了。nohup 加后台符号似乎成了默认方案:
bash复制nohup ./backup.sh > /var/log/backup.log 2>&1 &
这段命令的意思是把进程挂起,忽略终端断开信号,标准输出和标准错误全部重定向到日志文件,放到后台跑。这套方案对我的日常运维够用,但有个明显短板:没法重新把前台任务切回交互式界面。你如果想中途看进度、Ctrl+C 停掉再调整参数,是做不到的。
所以我更推荐用 tmux 管理长任务。tmux 的好处是任务跑在一个独立的会话里,SSH 断开任务继续跑,回来后可以恢复:
bash复制tmux new -s backup
# 在会话里执行 backup.sh
# Ctrl+B D 离开,但不中断
tmux attach -t backup
最近的云电脑和远程开发环境上,我尤其推荐 tmux,因为网络不稳时掉线太常见,tmux 基本从根上解决了长任务被误杀的问题。如果用的是 systemd 托管长期服务,其实不用 nohup 也合理,服务管理器自己会拉起进程并且管理标准输出。
2.4 systemd 服务管理:状态、日志、自启一气呵成
现在主流发行版服务都是 systemd 管理,服务状态排查的第一步是用 systemctl。判断一个服务是否“真的健康”,不能只看运行中三个字,还要看主进程号是否有变化、近期有没有重启、日志是不是持续输出。
bash复制systemctl status nginx
systemctl list-units --type=service --state=running
journalctl -u nginx --since "10 minutes ago"
排查 Nginx 为何不监听 80 端口,直接 systemctl status nginx 能看是否有重启痕迹,配合 journalctl -u 看最近十分钟日志,比到处翻 /var/log/nginx 下的 error.log 更快定位问题。服务配置常见问题是 ExecStart 命令写错路径、WorkingDirectory 目录不存在、启动顺序依赖没写清楚。给个最小可用的 service 文件例子:
ini复制[Unit]
Description=My Custom Service
After=network.target
[Service]
Type=simple
User=deploy
ExecStart=/opt/myapp/run.sh
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Type=simple 适合主进程占据前台的情况;Restart=on-failure 表示异常退出后 5 秒重启。写完配置后执行 systemctl daemon-reload 再 systemctl enable --now my-service,这样可以实现开机自启并立即启动。有一点别忽略:如果程序启动时需要联网,依赖 After=network.target 未必够,更稳的是 After=network-online.target 并且打开 Requires=network-online.target。
3. 系统性能监控与定时任务:把“无人值守”做扎实
3.1 监控四维:CPU、内存、IO、网络怎么配合看
性能监控我不只看 free -h 或者 top,实际排查时是一套组合拳。第一眼是 uptime,看 1 分钟、5 分钟、15 分钟平均负载。负载不是 CPU 使用率,它反映的是处于运行和不可中断状态的进程数量,但结合 CPU 核数才更有意义。
接下来看 vmstat:
bash复制vmstat 2 5
每两秒输出一次,共 5 次。重点看 r 列(运行队列)、us(用户态 CPU)、sy(内核态 CPU)、wa(等待 IO),还有 si/so 是否在持续交换内存。如果 wa 一直很高,多半是磁盘 IO 拖了后腿,这时候再上 iostat:
bash复制iostat -dx 2
看 %util 和 await。%util 接近吞吐上限但未必等于100%损坏,需要结合 await 和队列长度判断。io 问题排查最好的辅助工具是 pidstat,直接按进程看 IO:
bash复制pidstat -d 2
网络这块用 ss 查连接状态更直接,比如端口大量 TIME_WAIT 时,可以先看 ss -ant state time-wait,再去确认是连接池参数问题还是并发过高。
3.2 crontab 语法与真实场景:环境变量是最大的坑
定时任务几乎是每台服务器都会用到的系统管理功能。crontab 的基本格式是五个时间字段:
bash复制分 时 日 月 周 命令
一个每天凌晨 2 点清理 /tmp 下 7 天前文件的例子:
bash复制0 2 * * * find /tmp -type f -mtime +7 -delete >> /var/log/crontab_clean.log 2>&1
重点说两个坑。第一个是环境变量。cron 执行任务时的 PATH 非常精简,可能只有 /usr/bin:/bin,你自己手动跑正常的命令,cron 里却提示 command not found。解决方法是脚本开头重新加载环境,常用的是把命令写成绝对路径,或者脚本里 source /etc/profile 后再执行。第二个坑是日志会被系统邮件的默认机制吃掉。为避免这样,每个定时任务都要考虑把输出重定向到日志文件。
真正的生产建议:把复杂任务写成一个带日期后缀的日志文件,比如 tar 备份脚本里这样处理:
bash复制BACKUP_TIME=$(date +%Y%m%d_%H%M%S)
tar czf /backup/app_${BACKUP_TIME}.tar.gz /data/app
这样每次都有独立备份文件,排查问题时不会相互覆盖。
3.3 定时任务没人长时间运行会怎样:anacron 和 systemd timer
纯 crontab 有个问题:如果机器到点没开机,任务就跳过了。桌面与笔记本环境里我更倾向使用 anacron 或者 systemd timer。systemd timer 可以在错过计划时间后自动补跑,具体是用 OnCalendar 指定周期,再配合 Persistent=true 让错过的任务尽快执行。这套机制比 crontab 更可控,但配置复杂一点,适合需要更严谨记录的批量任务。
单一服务器的场景里,我用 crontab 占比仍然很高,因为它简单直观、排障成本低。如果你刚入门,优先把 crontab 用好;后边熟练了再换 systemd timer 做更复杂的调度。
4. LVM 与存储管理的实战边界:重装系统前的扩容和卸载
4.1 逻辑卷管理 LVM 到底是什么
热搜词里有一条:如果云电脑使用了 LVM(逻辑卷管理)并加入数据盘,重装前需要先从 LVM 卸载。这条信息在真实运维里非常重要,很多人不知道 LVM 怎么拆,就很容易把数据弄丢。
LVM 把存储分成三层:物理卷 PV、卷组 VG、逻辑卷 LV。物理卷就是一块磁盘或分区,卷组把多块物理卷合并成一个存储池,逻辑卷从这个池里划分出可挂载的空间。文件系统建在逻辑卷上,这也是它能在线扩容的基础。查看当前存储架构最常用的三条命令:
bash复制pvs
vgs
lvs
pvs 能看到物理盘被谁占用,vgs 看卷组还有多少剩余空间,lvs 看逻辑卷大小。装了系统又加过数据盘的情况下,如果数据盘已经被 vgextend 加进卷组,那格式化数据盘本身已经不会解除卷组关联了。
4.2 重装前要拆 LVM:完整卸载路径
重装系统最危险的操作,是安装程序识别到已有卷组,自动挂载在 /dev/mapper 下,让人产生“数据还在”的错觉,然后格式化步骤又把它误当成普通分区清理掉了。所以重装前,如果确认数据卷暂时不迁移,就要先从 LVM 逻辑卷层面解绑。
完整卸载流程我列出来:
bash复制umount /mnt/data # 先卸载挂载点
lvchange -an /dev/vg_data/lv_data # 禁用逻辑卷
vgchange -an /dev/vg_data # 禁用卷组
lvchange -an 的作用是让内核不再关联这个逻辑卷,vgchange -an 是让整个卷组离线。这两步做完,安装程序就不会再把这个 LVM 当活动卷组看到,数据盘即使插在机器里,也不会影响重装的初始化过程。
如果是想保留数据盘而重装系统盘,建议先把数据盘在 BIOS 或管理界面层面暂时解挂,重装完系统再插回去,这样风险最低。如果数据盘已经和系统盘在同一个卷组里,那更稳妥的做法是先备份重要数据,再把该卷组里的系统逻辑卷删掉,重建新的系统卷。这套操作明显复杂,所以生产环境建议把系统盘和数据盘分开用独立的 LVM 卷组来管理。
4.3 LVM 扩容:顺序错了会报错
在用的系统里,最常见需求是给一个挂载目录扩容。先说明,扩容顺序一定是先扩逻辑卷,再扩文件系统。用 ext4 系列文件系统时:
bash复制lvextend -L +20G /dev/vg_data/lv_data
resize2fs /dev/vg_data/lv_data
逻辑卷加 20G,resize2fs 把文件系统扩到跟上。如果文件系统是 XFS(比如很多 Linux 默认用 XFS),resize2fs 不适用,要改用:
bash复制xfs_growfs /mnt/data
XFS 文件系统设计上就是不支持缩小的,所以这一点务必提前知道。如果 lvextend 后忘了执行 resize,df -h 看到的空间不会变化,你会误以为扩容失败,实际是文件系统层还没跟上。执行完记得用 df -h 和 lsblk 双重确认。
5. 日志系统的管理:系统管理员的排障线索
5.1 journald 和 syslog:日志到底去哪了
接手一台新服务器的第一件事,我肯定会确认日志系统是否正常落盘。传统 syslog 体系下,/var/log/messages 或 /var/log/syslog 是最全局的日志文件;systemd 环境下,journald 把日志收进了二进制存储区,用 journalctl 查询。
journalctl 常用组合:
bash复制journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -f
journalctl --since "2025-01-01 00:00" --until "2025-01-01 23:59" -p err
-p err 是只看 error 级别以上,排查问题时能少看大量噪声。journald 日志默认是带这个时间戳和优先级的,排查服务反复重启问题时,先看每次都失败前的最后几行输出,比瞎猜原因可靠得多。如果你怀疑某个进程是收到信号后才退出的,还可以用 -o verbose 输出,里面带着进程号、用户 ID、触发来源,这是伪装的系统管理员最容易忽略的细节。
5.2 logrotate:日志不能无限增长
日志文件不轮转,最后结局就是磁盘满、业务写不了文件。很多人在机器上挂了几年才发现 /var/log 占据了大量空间。其实主流发行版都有 logrotate 基于 /etc/logrotate.conf 及 /etc/logrotate.d/ 自带配置,只是自定义应用的日志没有覆盖规则。
给一套常见的自定义配置,适用于按天滚动并保留 30 天:
code复制/var/log/custom-app/*.log {
daily
rotate 30
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
systemctl reload custom-app > /dev/null 2>&1 || true
endscript
}
daily 是每天切割一次,rotate 30 保留回 30 个文件,compress 压缩旧日志,sharedscripts 确保多条日志一次性执行一遍重载脚本。切割后立即 reload 服务,这是为了保证应用继续写旧文件描述符时能切换到新文件。
5.3 一个真实案例:应用升级后的“底层库版本”提示
排查业务系统问题,也经常落到系统管理范畴。遇到过用友 U8 从 8.90 版本升级到 18.0,登录软件提示“ufmeta 库是以前版本的数据,请使用系统管理”的情况。这个问题本质是版本升级后,应用系统自己管理的基础元数据库(ufmeta)里存的版本信息,和企业版的二进制程序版本不匹配了。
当时的排查思路是:先确认备份是否完整,再确认是不是直接通过附加老库的方式升级,导致系统库没被升级脚本更新。正确的解决方式是,升级前先做账套库和系统库的完整备份,然后严格按照软件要求的中间版本逐级升级结构,最后再执行应用升级工具去更新 ufmeta 系统库。
这个案例给我的感慨是,系统管理从来不只是操作系统管理,还包括数据库、中间件的版本管理和升级路径设计。很多人把系统管理等同于装系统、改网络、配用户,但在企业环境里,应用软件的系统库、日志、服务状态才是真正影响业务的核心,而这恰好也是信息系统管理工程师这一科目强调的内容。
写在最后:一点实际体会
用户管理和系统管理这些知识,表面上看起来零零散散,但在真实运维里它们永远交织在一起。没有用户体系,进程权限说不清楚;没有进程管理,定时任务挂了都不知道;没有存储和日志的认知,出了故障连排查入口都找不到。我这些年踩过最大的坑就是轻视基础、盲目上云原生和自动化工具,后来发现工具越复杂,越需要先把用户、系统、存储、日志这些基本功打扎实。打算考信息系统管理工程师的朋友,也别只背书,拿一台虚拟机把文中命令都跑一遍,收益比刷两遍题目大得多。
