0. 写在前面:为什么你需要“神器”而非“常用命令
这份手册更多是为了在突发的线上事故中,给 SRE 和运维工程师一条能立刻上手的“生路”。目标很直接——从问题出现到恢复可用,不超过半小时。无论是直接修复,还是找一条安全的绕行方案,重点是先让业务活过来,再慢慢分析原因。
每一个场景我都会给到清晰的路径,从现象到判断,再到可以直接敲的命令(附上模拟的控制台输入输出),最后还有验证环节和回退方案。为了避免误操作,这些涉及修改生产环境的步骤,都会有明显的提示,并建议在关键命令前加一道确认。命令和脚本只是参考,不是照抄即用的万能钥匙,最好在实际环境里先手动核对再执行。
下面这 12 个场景,我会直接展开一条条“半小时内能落地”的应急方案,并配上对应的模拟输出,方便你边看边做。
场景 一:服务进程直接崩溃或无法启动(systemd 服务 down)症状:用户报错 5xx,systemctl status 显示 failed。
时间预算:0–15 分钟(先恢复,再查原因)。
步骤与模拟
1. 检查服务状态:代码语言:javascript代码运行次数:0运行复制$ sudo systemctl status myapp.service --no-pager
● myapp.service - MyApp Service
Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2025-08-10 10:12:34 UTC; 3min 2s ago
Process: 12345 ExecStart=/usr/bin/myapp (code=exited, status=1/FAILURE)2. 看日志(journalctl):代码语言:javascript代码运行次数:0运行复制$ sudo journalctl -u myapp.service -n 200 --no-pager
Aug 10 10:12:30 host myapp[12345]: panic: listen tcp :8080: bind: address already in use
Aug 10 10:12:30 host systemd[1]: myapp.service: Main process exited, code=exited, status=1/FAILURE3. 若端口占用导致无法启动,定位占用:代码语言:javascript代码运行次数:0运行复制$ sudo ss -ltnp | grep :8080
LISTEN 0 128 0.0.0.0:8080 0.0.0.0:* users:(("oldproc",pid=12200,fd=10))4. 采取临时措施(优先不直接 kill,若确需释放端口,可 graceful 停止旧进程):代码语言:javascript代码运行次数:0运行复制# 通知并尝试优雅停止
$ sudo kill -TERM 12200
$ sudo systemctl restart myapp.service
# 模拟输出:
$ sudo systemctl restart myapp.service
# 无输出表示命令成功,检查状态:
$ sudo systemctl status myapp.service --no-pager
● myapp.service
Active: active (running) since Tue 2025-08-10 10:15:12 UTC验证:curl -I http://127.0.0.1:8080/health 返回 200。
代码语言:javascript代码运行次数:0运行复制$ curl -I http://127.0.0.1:8080/health
HTTP/1.1 200 OK
Content-Type: application/json回溯与防范:查进程为何残留(老进程未被正确回收、自动化重启策略冲突)。建议:增加 systemd 的 Restart=on-failure、在应用内处理端口冲突、添加启动时的端口自检测并退避机制。
场景二:应用或主机 CPU / 内存暴涨(性能退化)症状:响应变慢、请求超时、监控告警。
时间预算:0–20 分钟。
步骤与模拟
1. 快速查看主机资源:代码语言:javascript代码运行次数:0运行复制$ top -b -n1 | head -n5
top - 10:20:00 up 20 days, 3:44, 1 user, load average: 6.20, 5.90, 4.80
%Cpu(s): 95.0 us, 2.0 sy, 0.0 ni, 3.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 16000.0 total, 1200.0 free, 5000.0 used, 9800.0 buff/cache2. 找到耗资源进程:代码语言:javascript代码运行次数:0运行复制$ ps aux --sort=-%cpu | head -n 8
root 23456 92.3 5.1 1234567 800000 ? Ssl 10:19 120:34 /usr/bin/myapp --worker3. 若是单个进程短期占满,先限流或重启(优先平滑):代码语言:javascript代码运行次数:0运行复制# 若有 graceful restart 接口,优先调用(示例)
$ curl -X POST http://127.0.0.1:8080/admin/graceful-restart
{"status":"accepted"}
# 或 systemctl restart(谨慎)
$ sudo systemctl restart myapp.service4. 若是内存泄露导致持续增长,临时在流量层做流量削峰(调度到备用节点或缩减并发),例如在 nginx 上限制:代码语言:javascript代码运行次数:0运行复制# nginx 示例片段(仅供运维在配置管理中应用)
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;验证:观察 load 与响应恢复。
后续:收集 heap/pprof,做内存分析;在生产中部署资源限额(例如 cgroups、Kubernetes resource limits)。
场景三:磁盘满了,空间显示100%。
服务写日志失败、数据库写不了,这种情况不能拖。先看磁盘情况:
代码语言:javascript代码运行次数:0运行复制$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 50G 0 100% /找找哪里占地方最狠:
代码语言:javascript代码运行次数:0运行复制$ sudo du -shx /* 2>/dev/null | sort -hr | head -n 20
12G /var
8G /var/log
5G /var/lib/docker日志文件往往是罪魁祸首:
代码语言:javascript代码运行次数:0运行复制$ sudo ls -lhS /var/log | head -n 10
-rw-r--r-- 1 root root 6.8G Aug 10 09:50 app.log先别急着直接删,归档压缩更稳妥:
代码语言:javascript代码运行次数:0运行复制$ sudo mv /var/log/app.log /var/log/app.log.20250810
$ sudo gzip /var/log/app.log.20250810
$ sudo systemctl restart rsyslog
$ df -h | grep '/$'
/dev/sda1 50G 40G 10G 80% /千万别随便rm -rf,否则万一删错数据就麻烦了。后续得安排好 logrotate,或者把日志往对象存储推一波。
场景四:网络不通或者丢包,服务之间相互访问失败。
用户请求打不通,ping都没响应,先用最简单的 ping 确认:
代码语言:javascript代码运行次数:0运行复制$ ping -c 4 10.1.2.3
4 packets transmitted, 0 received, 100% packet loss再看端口监听情况:
代码语言:javascript代码运行次数:0运行复制$ sudo ss -tun state established '( dport = :3306 or sport = :3306 )'如果连接都没起来,检查路由配置:
代码语言:javascript代码运行次数:0运行复制$ ip route show
default via 10.1.1.1 dev eth0 proto static
10.1.0.0/16 dev eth0 proto kernel scope link src 10.1.2.5遇到这种问题,临时能做的就是把流量切换到健康节点,或者云环境确认安全组设置。
再用curl测试接口:
代码语言:javascript代码运行次数:0运行复制$ curl -sS -o /dev/null -w "%{http_code}\n" http://10.1.2.3:8080/health
200网络问题比较复杂,得后续排查链路和交换机。
场景五:DNS 解析突然失效,域名解析不到正确地址。
浏览器报找不到网站,先用dig查一下:
代码语言:javascript代码运行次数:0运行复制$ dig +short myservice.example.com @127.0.0.1
# 没有返回或者返回旧IP
$ dig +short myservice.example.com @8.8.8.8
203.0.113.23有时候本地DNS缓存问题,重启DNS服务或者清缓存可以试试。临时的话,也可以把IP写进/etc/hosts:
代码语言:javascript代码运行次数:0运行复制echo "203.0.113.23 myservice.example.com" | sudo tee -a /etc/hosts再试下ping:
代码语言:javascript代码运行次数:0运行复制$ ping -c1 myservice.example.com
PING myservice.example.com (203.0.113.23)后续要注意DNS TTL的设置,避免缓存问题。
场景六:HTTPS证书过期,用户浏览器报安全警告。
这个比较尴尬,先查证书有效期:
代码语言:javascript代码运行次数:0运行复制$ echo | openssl s_client -connect mysite.example.com:443 -servername mysite.example.com 2>/dev/null | openssl x509 -noout -dates
notBefore=Jun 10 00:00:00 2024 GMT
notAfter=Aug 10 09:00:00 2025 GMT证书快过期或者过期了得赶紧更新。临时能做的很少,可能让负载均衡器用备用证书,或者临时回退HTTP。
更新证书后别忘了reload nginx:
代码语言:javascript代码运行次数:0运行复制$ sudo cp cert.pem /etc/nginx/ssl/mysite.crt
$ sudo cp key.pem /etc/nginx/ssl/mysite.key
$ sudo systemctl reload nginx确认证书正常:
代码语言:javascript代码运行次数:0运行复制$ curl -sS -o /dev/null -w "%{ssl_verify_result}\n" https://mysite.example.com
0后面建议自动续期和提前预警。
场景七:数据库连接拒绝,或者主从切换失败。
应用报连接失败,先看看数据库进程:
代码语言:javascript代码运行次数:0运行复制$ sudo systemctl status mysqld --no-pager
● mysqld.service - MariaDB database server
Active: inactive (dead) since Tue 2025-08-10 10:05:12查看日志看看具体原因:
代码语言:javascript代码运行次数:0运行复制$ sudo tail -n 100 /var/log/mysqld.log
2025-08-10 10:04:58 0 [ERROR] InnoDB: Unable to allocate memory for the buffer pool如果主库挂了,赶紧看看有没有从库能顶上去:
代码语言:javascript代码运行次数:0运行复制$ mysql -uroot -p -e "STOP SLAVE; RESET SLAVE ALL;"然后把流量切过去。确认3306端口监听:
代码语言:javascript代码运行次数:0运行复制$ ss -ltnp | grep 3306
LISTEN 0 128 0.0.0.0:3306 0.0.0.0:* users:(("mysqld",pid=4567,fd=10))用mysqladmin ping确认数据库活着:
代码语言:javascript代码运行次数:0运行复制$ mysqladmin -uroot -p ping
mysqld is alive后续别忘了确保复制关系正常,自动故障转移配置好。
场景八:负载均衡后端全都挂了,流量被拒绝。
检查LB后端健康状态:
代码语言:javascript代码运行次数:0运行复制$ curl -sS http://127.0.0.1:8404; echo
# 看到 backend myapp-server1 DOWN check failed如果是误判,临时手动把节点标为健康:
代码语言:javascript代码运行次数:0运行复制echo "enable server mybackend/myserver1" | socat stdio /var/run/haproxy.sock如果后端真挂了,先下线故障节点,逐个恢复验证。
确认健康接口返回正常:
代码语言:javascript代码运行次数:0运行复制$ curl -I https://myapp.example.com/health
HTTP/1.1 200 OK建议改进健康检查逻辑,别只看单个点。
场景九:Kubernetes Pod一直CrashLoopBackOff或者被OOMKilled。
Pod频繁重启,先查Pod状态:
代码语言:javascript代码运行次数:0运行复制$ kubectl get pods -n prod -o wide
NAME READY STATUS RESTARTS AGE
myapp-5d9c6fcb6f-abcde 0/1 CrashLoopBackOff 36 2h详细事件看看:
代码语言:javascript代码运行次数:0运行复制$ kubectl describe pod myapp-5d9c6fcb6f-abcde -n prod
Events:
Warning BackOff 3m (x5 over 10m) kubelet Back-off restarting failed container查日志:
代码语言:javascript代码运行次数:0运行复制$ kubectl logs myapp-5d9c6fcb6f-abcde -n prod --previous
panic: runtime error: invalid memory address如果不急着修代码,先回滚版本或者扩容分摊压力:
代码语言:javascript代码运行次数:0运行复制$ kubectl rollout undo deployment/myapp -n prod
$ kubectl scale deployment myapp --replicas=5 -n prod确认Pod恢复:
代码语言:javascript代码运行次数:0运行复制$ kubectl get pods -n prod
NAME READY STATUS RESTARTS AGE
myapp-5d9c6fcb6f-xyz 1/1 Running 0 2m后续需要收集更多诊断信息,优化资源请求。
场景十:新版本部署失败,引发大面积故障,急需回滚。
观察到错误率飙升,第一时间暂停流水线:
代码语言:javascript代码运行次数:0运行复制$ curl -X POST -u admin:token "https://ci.example.com/api/v4/projects/1/pipelines/pause"看版本历史:
代码语言:javascript代码运行次数:0运行复制$ kubectl rollout history deployment/myapp -n prod
REVISION CHANGE-CAUSE
1 Initial deploy
2 Broken version回滚到稳定版本:
代码语言:javascript代码运行次数:0运行复制$ kubectl rollout undo deployment/myapp --to-revision=1 -n prod
deployment.apps/myapp rolled back确认恢复:
代码语言:javascript代码运行次数:0运行复制$ kubectl get deploy myapp -n prod
NAME READY UP-TO-DATE AVAILABLE AGE
myapp 5/5 5 5 15m以后要用蓝绿、金丝雀部署,避免上线直接断层。
场景十一:日志系统写入失败或者集中存储宕机。
日志写不进去了,先看看日志代理状态:
代码语言:javascript代码运行次数:0运行复制$ systemctl status fluentd
● fluentd.service - fluentd
Active: failed (Result: exit-code) since Tue 10:40日志里面查原因:
代码语言:javascript代码运行次数:0运行复制$ sudo tail -n 50 /var/log/fluentd/fluentd.log
Error: failed to push to ES: connection refused暂时改成写本地日志,待后续同步:
代码语言:javascript代码运行次数:0运行复制$ sudo systemctl restart fluentd确认本地日志还在流:
代码语言:javascript代码运行次数:0运行复制$ tail -n 10 /var/log/myapp/app.log
[2025-08-10T10:50:11Z] INFO request /api/health 200长远来看,要设计好缓冲和重试机制,避免单点堵塞。
场景十二:数据丢失,需要从备份快速恢复。
有备份才能快恢复,假设MySQL库备份在S3:
代码语言:javascript代码运行次数:0运行复制$ aws s3 cp s3://backups/mysql/prod_db_2025-08-10.sql.gz /tmp/
$ gunzip /tmp/prod_db_2025-08-10.sql.gz恢复到备用库,别直接覆盖生产:
代码语言:javascript代码运行次数:0运行复制$ mysql -uroot -p -e "CREATE DATABASE prod_db_restore;"
$ mysql -uroot -p prod_db_restore < /tmp/prod_db_2025-08-10.sql确认数据完好,再切流量。
etcd恢复更复杂,必须在维护窗口操作,示例:
代码语言:javascript代码运行次数:0运行复制$ ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/etcd/ca.crt --cert=/etc/etcd/client.crt --key=/etc/etcd/client.key snapshot save /tmp/snap.db
Saved snapshot at /tmp/snap.db
$ etcdctl snapshot restore /tmp/snap.db --data-dir /var/lib/etcd-from-backup每次应急结束,别忘了写记录,至少包括事件时间、影响、应急操作、验证结果和后续计划。只有这样,下次遇到类似状况才能更从容。
日常多练多演练,确保流程熟悉。别忘了,自动化和监控是最好的防线,能让你第一时间发现和定位问题。
救火不易,祝你平安。
老杨时间这里我先声明一下,日常生活中大家都叫我波哥,跟辈分没关系,主要是岁数大了.就一个代称而已.
我的00后小同事我喊都是带哥的.张哥,李哥的.
但是这个称呼呀,在线下参加一些活动时.金主爸爸也这么叫就显的不太合适.
比如上次某集团策划总监,公司开大会来一句:“今个咱高兴!有请IT运维技术圈的波哥讲两句“
这个氛围配这个称呼在互联网这行来讲就有点对不齐!
每次遇到这个情况我就想这么接话: “遇到各位是缘分,承蒙厚爱,啥也别说了,都在酒里了.我干了,你们随意!”
所以以后咱们改叫老杨,即市井又低调.还挺亲切,我觉得挺好.
运维X档案系列文章:
从告警到CTO:一个P0故障的11小时生死时速
老杨的关于AI的号