大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
操作系统
这一课你将能做到
- 用 SSH 登录一台 Linux 服务器,完成文件、进程、权限、端口的日常操作
- 用 systemd 把 Spring Boot 应用注册为开机自启、挂了自动重启的系统服务
- 服务器出问题时,用 top/free/df/ss/journalctl 等命令定位资源瓶颈
为什么要学
你部署应用的每一台云服务器,99% 跑的是 Linux。你的 Spring Boot 进程、MySQL、Redis、Nginx 全都是 Linux 上的进程;日志是 Linux 文件;访问控制是 Linux 权限;性能瓶颈要用 Linux 命令排查。不会 Linux 的 DevOps 等于不会游泳的救生员。
人话:Windows 是你日常用的桌面,点点鼠标就能干活;Linux 是服务器的操作系统,没有图形界面,一切靠命令行。刚开始不适应,但命令行的优势是「可脚本化」——你能把 100 条命令写进一个脚本一键执行,鼠标点 100 次可没法录制回放。
先建立图像
Linux 系统的分层和关键目录:
┌─────────────────────────────────────┐
│ 你的应用:java 进程 / nginx / mysqld │ ← 用户态
├─────────────────────────────────────┤
│ 系统调用接口(open/read/write/...) │
├─────────────────────────────────────┤
│ Linux 内核:进程调度/内存/文件系统/网络 │ ← 内核态
├─────────────────────────────────────┤
│ 硬件:CPU / 内存 / 磁盘 / 网卡 │
└─────────────────────────────────────┘
关键目录:
/etc 配置文件(nginx.conf、systemd 单元)
/var/log 日志(系统日志、nginx 日志)
/opt 第三方应用安装目录(你的 jar 放这)
/home 普通用户家目录
/root root 用户家目录
/tmp 临时文件(重启清空)
/usr/bin 系统命令
进程与端口的关系:
ss -tlnp 输出示例:
LISTEN 0 100 0.0.0.0:22 用户 sshd(远程登录)
LISTEN 0 100 0.0.0.0:80 用户 nginx(HTTP)
LISTEN 0 100 127.0.0.1:3306 用户 mysqld(只监听本机,安全)
LISTEN 0 100 127.0.0.1:8080 用户 java(被 nginx 反代,不直接暴露)
跟着做
步骤 1:登录服务器,建立基本操作肌肉记忆
# 登录(把 IP 换成你的服务器)
ssh root@1.2.3.4
# 我在哪?我是谁?
pwd && whoami && hostname
# 文件操作四件套
mkdir -p /opt/app && cd /opt/app
ls -la # 看文件列表(含权限、属主)
cat /etc/os-release # 看系统版本
cp app.log app.log.bak # 复制
mv app.log.bak /tmp/ # 移动/重命名
步骤 2:权限与属主——Linux 安全的核心
# 创建专用用户跑应用(不要用 root)
useradd -r -s /sbin/nologin appuser
# 把应用目录交给它
chown -R appuser:appuser /opt/app
# 理解权限数字:r=4 w=2 x=1
chmod 755 deploy.sh # 所有者可读写执行,其他人只读执行
chmod 600 ~/.ssh/id_rsa # 私钥必须只有本人可读
ls -l # -rwxr-xr-x 1 appuser appuser ... 对照看
步骤 3:进程管理——你的 Java 应用就是一个进程
# 找进程
ps aux | grep java
pgrep -f 'app.jar' # 只拿 PID,脚本里好用
# 看资源占用(按 P 排序 CPU,按 M 排序内存,q 退出)
top
# 杀掉进程
kill 12345 # 发 TERM 信号,让它优雅退出
kill -9 12345 # 强杀,只在 TERM 无效时用
步骤 4:用 systemd 把 Spring Boot 管起来(生产标准做法)
创建 /etc/systemd/system/myapp.service:
[Unit]
Description=MyApp Spring Boot Service
After=network.target mysqld.service redis.service
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/app
ExecStart=/usr/bin/java -jar /opt/app/app.jar --spring.profiles.active=prod
Restart=always
RestartSec=5
SuccessExitStatus=143
Environment="JAVA_OPTS=-Xms512m -Xmx1024m"
[Install]
WantedBy=multi-user.target
然后:
systemctl daemon-reload # 改配置后必执行
systemctl enable myapp # 开机自启
systemctl start myapp # 启动
systemctl status myapp # 看状态
journalctl -u myapp -f # 实时看应用日志(比 tail nohup.out 优雅)
journalctl -u myapp --since "1 hour ago" | grep -i error
这就解决了第 1 课 nohup & 裸跑的所有问题:进程挂了 5 秒后自动拉起、服务器重启自动启动、日志被 systemd 统一收集。
步骤 5:资源排查命令组合拳
# 内存:还剩多少?buff/cache 可以被回收,重点看 available
free -h
# 磁盘:哪个分区满了?
df -h
du -sh /var/log/* | sort -rh | head # 找出占空间的大户
# 端口与连接
ss -tlnp # 谁在监听端口
ss -s # 连接数统计
# 系统负载:三个数分别是 1/5/15 分钟平均负载
# 负载持续 > CPU 核数,说明系统忙不过来
uptime
# 日志关键字统计:今天有多少 ERROR?
grep -c ERROR /var/log/myapp/app.log
讲清楚要点
- 一切皆文件:Linux 里硬件是文件(
/dev)、进程信息是文件(/proc/1234/)、配置是文件。理解了这点,就理解为什么cat /proc/cpuinfo能看 CPU。 - 权限最小化原则:应用用普通用户跑、数据库只监听 127.0.0.1、SSH 禁密码用密钥。每一步都在缩小被攻击的面。
- 进程管理交给 systemd:不要自己写 nohup 脚本。systemd 提供自动重启、日志、依赖顺序、资源限制,是发行版标配。
- 日志是第一排查入口:应用日志
journalctl -u myapp,系统日志journalctl -xe,养成「先看日志再猜原因」的习惯。 - 资源四问:CPU 高不高(top)?内存够不够(free)?磁盘满不满(df)?端口对不对(ss)?90% 的线上问题用这四个命令就能定位大方向。
你可能会懵的地方
-
Linux 发行版这么多,学哪个? 服务器领域主流是 Ubuntu LTS 和 CentOS 系(现在多是 Rocky/Alma)。命令 90% 通用,差别主要在包管理器:Ubuntu 用
apt install,CentOS 系用dnf install。学会一个另一个自然通。 -
sudo 和 root 到底什么关系? root 是超级管理员,权限无限大。直接用 root 操作,一条
rm -rf打错目录就是事故。sudo 让普通用户「临时借用」root 权限执行单条命令,且有日志可查。生产环境标准做法:禁用 root 直接登录,普通用户 + sudo。 -
kill -9为什么危险?kill(TERM 信号)是告诉进程「请收拾一下退出」,Java 进程可以执行 shutdown hook 释放连接;kill -9(KILL 信号)是内核直接掐死,进程没有任何收拾机会,可能导致数据写一半、连接泄漏。 -
负载 4.0 是高还是低? 看 CPU 核数。4 核机器负载 4.0 是「刚好满载」,8 核就是「很闲」。经验值:持续超过核数就要警惕,超过核数 2 倍必须处理。
-
为什么数据库要绑定 127.0.0.1? MySQL 绑定 0.0.0.0 意味着任何能连到这台机器的人都能尝试登录数据库。绑定 127.0.0.1 后只有本机的应用能连,外面根本摸不到 3306 端口,安全性天壤之别。如果必须远程访问,也应该走 SSH 隧道。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
chmod 777 图省事 | 任何人可改写,安全事故温床 | 最小够用:目录 755、文件 644、私钥 600 |
| 用 root 跑 Java 应用 | 应用被攻破 = 服务器被攻破 | 专用用户 + nologin shell |
rm -rf /tmp/ xxx(中间多个空格) | 把 /tmp/ 删了 | 删前先 ls 确认路径,脚本里变量加引号 |
| 日志不切割,磁盘被撑满 | 应用写不了日志甚至系统异常 | 配 logrotate 或让 systemd 管日志 |
| 改完 systemd 单元忘了 daemon-reload | 旧配置还在生效 | systemctl daemon-reload 再 restart |
卡点急救
- 磁盘 100% 应用狂报错:
df -h找满的分区 →du -sh /* 2>/dev/null | sort -rh | head定位大户(通常是日志)→ 清理后立即配 logrotate 防止复发。 - Java 进程 CPU 100%:
top -Hp <pid>找到吃 CPU 的线程 → 把线程 ID 转 16 进制 →jstack <pid> | grep <nid>看是哪个方法在死循环。 - 改完配置 restart 失败:
systemctl status myapp看概要 →journalctl -u myapp -n 50 --no-pager看具体报错,90% 是路径或权限写错。
面试常问
-
如何排查服务器负载高? 先
uptime确认负载确实高且持续 →top看是 CPU 高还是 IO 等待(wa 高)→ CPU 高用top -Hp定位线程,Java 应用结合 jstack 分析;IO 高用iostat或iotop定位进程 → 内存问题看free和是否 OOM(dmesg | grep -i oom)。 -
Linux 进程状态有哪些? R(运行/就绪)、S(可中断睡眠,大部分进程常态)、D(不可中断睡眠,通常是等 IO,D 多了要小心)、Z(僵尸进程,父进程没回收,要找父进程)、T(停止)。
-
软硬链接的区别? 硬链接是同一个 inode 的多个名字,删一个文件内容还在,不能跨文件系统、不能链目录;软链接(ln -s)是一个指向路径的快捷方式,源文件删了就失效,可跨文件系统。部署里的
current -> releases/v1.2.3软链切换就是经典的蓝绿发布雏形。
自测三问
- 不看笔记写出:查看端口监听、查看磁盘使用、查看进程内存占用的命令。
- 为什么生产环境不推荐
nohup java -jar &而是推荐 systemd?至少说出两个理由。 chmod 644 application.yml里 6、4、4 分别代表什么权限?属主是谁的概念?
小结一句话
Linux 是 DevOps 的地基:文件、权限、进程、日志、资源五块肌肉练熟,后面所有工具都长在这块地基上。
延伸
- Linux Journey(免费英文教程)
- 下一课:Git 与 GitHub——代码的版本控制与协作,是所有自动化的起点。