前面十三天学的是工具,今天是把工具连成流程。排障能力不是读出来的,是修出来的。
Day 02 的规矩,今天正式用上:
sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%F)
有了这个,今天你可以放心大胆地搞破坏。
标准排障流程
- 1 · systemctl status
- 看
Active是什么状态,顺便读最后那几行日志——原因经常直接就在那。 - 2 · journalctl -xe
- 看详细报错。这一步能定位到具体是哪类问题。
- 3 · 配置语法检查
- nginx 用
nginx -t,sshd 用sshd -t。它会告诉你第几行错。 - 4 · 端口占用
ss -tunlp | grep 端口号——是不是别的进程先占了。- 5 · 权限 / SELinux
- 前面都对还起不来,查这个。第 19 天详讲。
故障一:配置语法错
$ sudo vi /etc/nginx/nginx.conf
# 找到任意一行结尾的分号,把它删掉
# 比如把 listen 80;
# 改成 listen 80
# 然后 Esc → :wq 保存
$ sudo systemctl restart nginx
Job for nginx.service failed because the control process exited with error code.
See "systemctl status nginx.service" and "journalctl -xe" for details.
$ systemctl status nginx
Active: failed (Result: exit-code) since ...
Process: 4102 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=1)
↑ 已经能看出是配置检查那一步挂的
$ sudo journalctl -xe | tail -20
nginx: [emerg] directive "listen" is not terminated by ";" in
/etc/nginx/nginx.conf:47
↑ 报错说得很清楚:第 47 行,缺分号
$ sudo nginx -t
nginx: [emerg] directive "listen" is not terminated by ";" in /etc/nginx/nginx.conf:47
nginx: configuration file /etc/nginx/nginx.conf test failed
$ sudo vi /etc/nginx/nginx.conf
:47 ← Day 04 学的,直接跳到第 47 行
i 加回分号 → Esc → :wq
$ sudo nginx -t ← 改完先检查,别直接重启
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl restart nginx
$ systemctl status nginx ← 确认 active (running)
改完配置,先 nginx -t 检查,再 systemctl reload。
生产环境上如果直接 restart,配置有错就是一次真实的服务中断;先 -t 检查的话,错了也只是你自己看到一行报错,服务还好好跑着。
这个习惯本身就是一个能在面试里讲的点。
故障二:端口被占
$ sudo systemctl stop nginx
# 用别的东西把 80 端口占住
$ sudo python3 -m http.server 80 &
$ sudo systemctl start nginx
Job for nginx.service failed ...
$ sudo journalctl -xe | tail -10
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
↑ 端口被占用,说得明明白白
$ sudo ss -tunlp | grep :80
tcp LISTEN 0 5 0.0.0.0:80 0.0.0.0:* users:(("python3",pid=4321,fd=3))
↑ 找到是谁占的:python3,PID 4321
$ sudo kill 4321 # Day 11 学的,先温和地停
$ sudo ss -tunlp | grep :80 # 确认端口空出来了
$ sudo systemctl start nginx
$ systemctl status nginx
真实环境里发现端口被占,第一反应不该是杀掉对方——先搞清楚那是什么服务、是不是更重要。
要么改自己服务的端口,要么跟对方的负责人确认后再动。这个判断力比命令更重要。
故障三:文件权限
$ sudo chmod 000 /usr/share/nginx/html/index.html
$ curl -I http://127.0.0.1
HTTP/1.1 403 Forbidden
# 第一层:nginx 以谁的身份跑
$ ps aux | grep "nginx: worker" | head -1
nginx 4501 ... nginx: worker process
# 第二层:文件权限和属主
$ ls -l /usr/share/nginx/html/index.html
----------. 1 root root 612 ... index.html
↑ 000,谁都读不了 —— 原因找到
# 看 nginx 自己的错误日志,会说得更直白
$ sudo tail -3 /var/log/nginx/error.log
[error] open() "/usr/share/nginx/html/index.html" failed (13: Permission denied)
$ sudo chmod 644 /usr/share/nginx/html/index.html
$ curl -I http://127.0.0.1
HTTP/1.1 200 OK
权限问题改完立刻生效,nginx 不需要 reload——因为它是每次请求时才去读文件的。
分清「改配置要重载」和「改数据不用重载」,能省下不必要的服务中断。
把今天串成一个面试故事
「有次改完 nginx 配置重启,服务起不来。我先看 systemctl status,显示 failed 在配置检查那一步;再 journalctl -xe,报错直接给出了文件名和行号——第 47 行少个分号。用 vi 的 :47 跳过去补上,nginx -t 检查通过后再 reload。」
「后来我养成了习惯:改完配置一定先 nginx -t 再重载,避免线上直接挂掉。」
有现象、有排查步骤、有工具、有结果,最后还有一个改进的习惯——这就是一个完整的故事。
今天的实战
今天时间会比平时长,但值得。请务必自己动手,不要只读。
- 先备份:
sudo cp -a /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%F) - 故障一:删掉一个分号 → 重启失败 → 不看本页,自己按 status → journalctl -xe → nginx -t 的顺序找出行号 → 修复 → 验证
- 故障二:用
sudo python3 -m http.server 80 &占住端口 → 启动 nginx 失败 → 用ss -tunlp找出占用者 → 处理 → 验证 - 故障三:
chmod 000首页 →curl -I看到 403 → 按三层顺序排查 → 修复 → 再 curl 确认 200 - 最后:把整个过程用自己的话讲一遍(说出声),就当面试在问你
卡住是好事,说明找到了你的薄弱点。先别翻答案——回到对应那天的页面重看一遍(Day 12 systemctl / Day 13 journalctl / Day 07 属主权限),再回来试。
实在不行,你还有备份:sudo cp -a /etc/nginx/nginx.conf.bak.* /etc/nginx/nginx.conf。
Day 15 是机动日,不学新东西——凭记忆默写前三周的命令,找出自己的漏洞。
到明天为止,你就走完一半了。