Linux 系统
服务器世界的通用语言。这一页解决三个问题:东西放在哪、怎么高效操作、出问题怎么查。
01目录结构与规范
一切皆文件。先搞清楚文件系统的骨架,后面所有操作才有坐标系。
Linux 只有一个根目录 /,所有设备、分区都挂载到这棵树上。理解目录职责,能避免「把数据放错地方」这类低级事故。
| 目录 | 用途 | 备注 |
|---|---|---|
/bin /sbin | 基础命令 | 现代发行版多软链到 /usr/bin |
/etc | 配置文件 | 改配置优先来这里 |
/home /root | 普通用户 / root 家目录 | 业务数据不放这里 |
/var | 可变数据:日志、缓存、队列 | /var/log 是排障第一站 |
/usr | 安装的软件与库 | /usr/local 放手工编译软件 |
/opt | 第三方独立软件 | 整体安装、整体删除 |
/tmp | 临时文件 | 可能被系统定期清理,别存重要数据 |
/proc /sys | 内核与进程的虚拟文件系统 | 只存在于内存,用于查看运行时状态 |
/dev | 设备文件 | /dev/sda、/dev/null |
查看目录占用的两条命令
# 树形展示两层目录
tree -L 2 -d /etc
# 按大小排序查看当前目录各子目录占用(人类可读)
du -sh ./* 2>/dev/null | sort -hr | head -10
# 整盘使用率
df -hT
df -h 看的是文件系统剩余空间,du -sh 看的是文件实际占用。两者差异大,通常是有进程持有已删除文件的句柄(lsof | grep deleted 可验证)。
02文件与目录操作
最高频的一类命令,目标是脱离鼠标、键盘完成一切。
基础操作
ls -alh # 详细列表,人类可读大小,含隐藏文件
cd - # 回到上一个目录
cp -a src/ dst/ # 递归复制并保留权限、时间戳
mv old.txt new.txt # 重命名 / 移动
rm -i file # 删除前确认(推荐加 alias)
ln -s /opt/app/current /opt/app/run # 软链接,常用于版本切换
mkdir -p /data/app/{logs,conf,data} # 一次创建多级 + 多目录
高危:rm -rf /、rm -rf $VAR/(VAR 为空时会变成删根)。写删除命令时坚持三个习惯:变量加引号并校验、先 ls 确认、必要时用 -i。
查找:find 与 locate
# 按名称 + 类型查找
find /var/log -type f -name "*.log" -size +100M
# 按修改时间查找(7 天以前)
find /data -type f -mtime +7
# 查找到后批量执行(比 xargs 更安全,可配合 -print0 处理空格文件名)
find /tmp -name "*.tmp" -print0 | xargs -0 rm -f
# 数据库索引查找,速度快但可能不是最新
locate nginx.conf
sudo updatedb # 手动重建索引
查看文件内容的取舍
| 命令 | 场景 |
|---|---|
cat | 小文件、配合管道 |
less | 大文件阅读,支持 / 搜索、G 跳尾、q 退出 |
head -n 50 | 看开头,如日志头部有启动信息 |
tail -f / tail -F | 实时追踪日志;-F 在文件被切割重建后仍能跟踪 |
wc -l | 统计行数,比大小更能反映日志量 |
03用户、权限与属主
权限问题是非 root 用户 80% 报错的根因。
执行 ls -l 会看到 -rwxr-xr-- 这样的 10 个字符:第 1 位是类型(- 文件、d 目录、l 软链),后面 9 位每 3 位一组,分别代表属主、属组、其他人的 r/w/x。
| 数字 | 权限 | 含义 |
|---|---|---|
| 4 | r | 读 |
| 2 | w | 写 |
| 1 | x | 执行 / 对目录表示可进入 |
chmod 644 app.conf # rw-r--r--
chmod 755 deploy.sh # rwxr-xr-x
chmod +x script.sh # 追加执行权限
chmod -R u+w,g-w dir/ # 用符号模式微调
chown appuser:appgroup -R /data/app
chgrp devs report.txt
umask # 默认权限掩码,普通用户通常 0022
# 特殊权限
chmod u+s /usr/bin/passwd # setuid:以属主身份执行
chmod g+s /data/share # setgid:目录下新建文件继承属组
chmod +t /data/share # sticky:仅属主可删除自己的文件,如 /tmp
提权与切换
sudo -u appuser whoami # 以指定用户身份执行
sudo -i # 切换到 root 的登录 shell
su - appuser # 完全切换用户(加载其环境变量)
# 只读 /etc/sudoers,务必用 visudo 编辑(会做语法校验)
sudo visudo
看到 Permission denied 先执行 namei -l /path/to/file,它会逐级列出每一层目录的权限。目录缺少 x 权限时,即使文件本身可读也访问不了。
04进程与 systemd
服务起不来、进程杀不掉、开机不自动运行,都在这一节。
进程查看与信号
ps -ef | grep java # 传统写法
ps aux --sort=-%mem | head # 按内存排序
pgrep -af java # 直接按名字找 PID 并显示命令行
pstree -p 1234 # 看进程树,判断父子关系
top # 交互式,按 M 内存排序、P CPU 排序、1 展开核心
kill -15 1234 # SIGTERM,优雅退出(首选)
kill -9 1234 # SIGKILL,强杀,可能丢数据
pkill -f "app.jar" # 按命令行匹配杀进程
nohup java -jar app.jar > app.log 2>&1 & # 后台常驻(简易方案)
jobs / fg / bg # 作业控制
systemd 管理服务
生产环境更推荐用 systemd 托管进程:开机自启、崩溃重启、日志统一收集。
# /etc/systemd/system/myapp.service
[Unit]
Description=My Java Application
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/app
ExecStart=/usr/bin/java -jar /opt/app/app.jar
Restart=on-failure
RestartSec=5
SuccessExitStatus=143
Environment="JAVA_OPTS=-Xms512m -Xmx1g"
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload # 改完 unit 文件必须执行
sudo systemctl enable --now myapp # 开机自启并立即启动
systemctl status myapp # 查看状态与最近日志
systemctl restart myapp
journalctl -u myapp -f # 实时跟踪服务日志
journalctl -u myapp --since "10 min ago" -p err # 只看错误级别
Restart=on-failure 只在非正常退出时重启。若 Java 进程收到 SIGTERM(143)退出属于正常,需用 SuccessExitStatus 显式声明,否则会被反复重启。
05文本三剑客:grep / sed / awk
日志分析的核心武器,能省下大量「肉眼找」的时间。
grep:过滤
grep -rn "TODO" src/ # 递归 + 显示行号
grep -i "error" app.log # 忽略大小写
grep -v "^#" nginx.conf # 排除注释行
grep -c "500 " access.log # 统计匹配行数
grep -A3 -B1 "Exception" app.log # 显示匹配行前后 3 行 / 1 行
grep -E "Timeout|Refused" app.log # 扩展正则,多关键词
grep -o '"[A-Z]*"' file # 只输出匹配部分
sed:替换与提取
sed -n '100,200p' app.log # 打印 100-200 行
sed 's/localhost/10.0.0.5/g' conf.txt # 全局替换(仅输出,不改文件)
sed -i.bak 's/8080/9090/g' app.yml # 原地修改并备份
sed '/^$/d' file # 删除空行
sed -n '/ERROR/,/END/p' app.log # 打印两个模式之间的内容
sed -i 会直接改文件。在关键配置上先用不带 -i 的形式确认输出,或加 .bak 备份后缀。
awk:按列处理与统计
# 打印第 1、7 列(常用:用户名、命令)
ps -ef | awk '{print $1, $7}'
# 以 : 分隔,筛选第 3 列大于 1000 的行
awk -F: '$3 > 1000 {print $1}' /etc/passwd
# 统计访问日志中各状态码出现次数
awk '{print $9}' access.log | sort | uniq -c | sort -nr
# 求某列总和
awk '{sum += $5} END {print sum/1024/1024 " MB"}' data.txt
# 输出行号与内容
awk '{printf "%5d %s\n", NR, $0}' file
组合技:一条命令定位日志
# 统计最近 1 小时内每个接口的 TOP 10 耗时
awk -v since="$(date -d '1 hour ago' +%H:%M:%S)" '$0 >= since' app.log \
| awk '{print $7, $NF}' \
| sort -k2 -nr | head -10
06网络与端口排查
「服务连不上」的排查顺序:本机监听 → 防火墙 → 路由 → DNS。
查看监听与连接
ss -tulnp # 等价于 netstat -tulnp,更现代快速
ss -tnp state established # 只看已建立的连接
lsof -i:8080 # 谁占用了 8080
fuser -k 8080/tcp # 强制结束占用该端口的进程(谨慎)
curl -v http://127.0.0.1:8080/health # 带过程详情
curl -o /dev/null -s -w '%{http_code} %{time_total}s\n' https://example.com
telnet 10.0.0.5 3306 # 测端口连通性(未安装可用 nc -zv)
防火墙
# firewalld
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-port=8080/tcp && sudo firewall-cmd --reload
# ufw (Debian/Ubuntu)
sudo ufw status verbose
sudo ufw allow 8080/tcp
# iptables 查看规则(只读,勿随意修改)
sudo iptables -L -n -v --line-numbers
路由与 DNS
ip addr show # 查看网卡与 IP(替代 ifconfig)
ip route show # 查看路由表与默认网关
ping -c 4 8.8.8.8 # 通 = 网络可达
ping -c 4 example.com # 不通但上面通 = DNS 问题
cat /etc/resolv.conf # 查看 DNS 配置
dig +short example.com # 精确查询解析结果
traceroute example.com # 逐跳定位链路中断位置
排查顺序建议固定:ss -tulnp 确认进程是否在听 → curl 127.0.0.1 确认本机可用 → telnet 从外部测端口 → 查防火墙与安全组。逐层收敛,不要跳步。
07磁盘、内存与性能排查
掌握「四看」:看负载、看 CPU、看内存、看 IO。
整体负载
uptime
# load average: 1.20, 0.98, 0.75
# 三个值分别是 1、5、15 分钟平均负载;
# 可运行任务数 = load / 核心数,持续 > 1 说明有排队
内存
free -h
# 关注 available 列,而不是 free 列(buff/cache 可被回收)
vmstat 1 5
# si/so 持续非 0 说明正在使用交换分区,性能会明显下降
# 找出吃内存的进程
ps aux --sort=-%mem | head -5
# 定位 OOM 记录
dmesg | grep -i "out of memory"
journalctl -k | grep -i oom
CPU 与热点线程
top -H -p 1234 # 查看某进程的线程级 CPU 占用
# 找到高占用线程 TID 后,转十六进制
printf '%x\n' 12345
# 再用 jstack 定位 Java 代码
jstack 1234 | grep -A 20 "0x3039"
磁盘 IO
iostat -x 1 5
# %util 接近 100% 表示设备饱和;await 明显偏高说明有 IO 等待
iotop -o # 找出读写最多的进程(需 root)
lsof /data/app.log # 哪个进程打开了该文件
# 磁盘空间不足的常见位置
du -sh /var/log/* | sort -hr | head
find / -xdev -size +1G -type f 2>/dev/null # 找出超大文件
一句话排障口诀
负载高但 CPU 不高
多为 IO 等待或锁竞争,查 iostat 与 vmstat 的 b、wa 列。
内存持续上涨
先区分是缓存还是泄漏,看 available;再结合 pmap、jmap 定位。
磁盘写满但找不到大文件
检查被删除但仍被占用的句柄:lsof | grep deleted。
服务偶发超时
看 ss -s 的 TIME_WAIT、连接队列,以及文件描述符上限 ulimit -n。
08自测清单
勾选表示已动手验证过,进度会保存在本地浏览器中。
你应该能不查资料完成以下操作
- 用一条命令找出
/var/log下大于 100MB 的文件 - 解释
chmod 750的含义,并说出755与644的适用场景 - 用
namei -l定位一次Permission denied - 写一个 systemd unit 并实现开机自启 + 崩溃重启
- 用
awk统计 Nginx 访问日志中状态码为 500 的请求数 - 用
sed -i批量替换配置文件中的端口并保留备份 - 按「本机监听 → 防火墙 → 路由 → DNS」顺序排查一次连接不通
- 通过
top -H+jstack找到 Java 进程中最耗 CPU 的代码行 - 说出 load average 与 CPU 核心数的关系,并判断当前机器是否过载
- 解释
free中free与available的区别
完成 8 项以上,就可以进入 Java 语言 模块了。Linux 的很多能力是在真实故障中长出来的,保持记录习惯即可。