CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
操作系统
这一课你将能做到
用 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 的地基:文件、权限、进程、日志、资源五块肌肉练熟,后面所有工具都长在这块地基上。
延伸