您当前位置:网站首页 >> 福利吧 >> 技术教程 >> 运维应急手册:30 分钟内恢复服务的 12 个场景(运维工程师必备)

运维应急手册:30 分钟内恢复服务的 12 个场景(运维工程师必备)

时间:2025-09-28 05:15:15  来源: IT运维技术圈    作者: 静静和小沐沐   浏览:101

 


 

 

 







 

 0. 写在前面:为什么你需要“神器”而非“常用命令

 

 

 

这份手册更多是为了在突发的线上事故中,给 SRE 和运维工程师一条能立刻上手的“生路”。目标很直接——从问题出现到恢复可用,不超过半小时。无论是直接修复,还是找一条安全的绕行方案,重点是先让业务活过来,再慢慢分析原因。

每一个场景我都会给到清晰的路径,从现象到判断,再到可以直接敲的命令(附上模拟的控制台输入输出),最后还有验证环节和回退方案。为了避免误操作,这些涉及修改生产环境的步骤,都会有明显的提示,并建议在关键命令前加一道确认。命令和脚本只是参考,不是照抄即用的万能钥匙,最好在实际环境里先手动核对再执行。

下面这 12 个场景,我会直接展开一条条“半小时内能落地”的应急方案,并配上对应的模拟输出,方便你边看边做。

场景 一:服务进程直接崩溃或无法启动(systemd 服务 down)

症状:用户报错 5xx,systemctl status 显示 failed。
时间预算:0–15 分钟(先恢复,再查原因)。

步骤与模拟

  1. 1. 检查服务状态:
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)
  1. 2. 看日志(journalctl):
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/FAILURE
  1. 3. 若端口占用导致无法启动,定位占用:
sudo ss -ltnp | grep :8080
LISTEN 0      128         0.0.0.0:8080       0.0.0.0:*    users:(("oldproc",pid=12200,fd=10))
  1. 4. 采取临时措施(优先不直接 kill,若确需释放端口,可 graceful 停止旧进程):
# 通知并尝试优雅停止
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。

$ 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. 1. 快速查看主机资源:
$ 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/cache
  1. 2. 找到耗资源进程:
$ ps aux --sort=-%cpu | head -n 8
root     23456 92.3  5.1 1234567 800000 ?    Ssl  10:19  120:34 /usr/bin/myapp --worker
  1. 3. 若是单个进程短期占满,先限流或重启(优先平滑):
# 若有 graceful restart 接口,优先调用(示例)
$ curl -X POST http://127.0.0.1:8080/admin/graceful-restart
{"status":"accepted"}
# 或 systemctl restart(谨慎)
sudo systemctl restart myapp.service
  1. 4. 若是内存泄露导致持续增长,临时在流量层做流量削峰(调度到备用节点或缩减并发),例如在 nginx 上限制:
# nginx 示例片段(仅供运维在配置管理中应用)
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;

验证:观察 load 与响应恢复。

后续:收集 heap/pprof,做内存分析;在生产中部署资源限额(例如 cgroups、Kubernetes resource limits)。


场景三:磁盘满了,空间显示100%。

服务写日志失败、数据库写不了,这种情况不能拖。先看磁盘情况:

df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   50G     0 100% /

找找哪里占地方最狠:

sudo du -shx /* 2>/dev/null | sort -hr | head -n 20
12G /var
8G  /var/log
5G  /var/lib/docker

日志文件往往是罪魁祸首:

sudo ls -lhS /var/log | head -n 10
-rw-r--r-- 1 root root 6.8G Aug 10 09:50 app.log

先别急着直接删,归档压缩更稳妥:

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 确认:

$ ping -c 4 10.1.2.3
4 packets transmitted, 0 received, 100% packet loss

再看端口监听情况:

sudo ss -tun state established '( dport = :3306 or sport = :3306 )'

如果连接都没起来,检查路由配置:

$ 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测试接口:

$ curl -sS -o /dev/null -w "%{http_code}\n" http://10.1.2.3:8080/health
200

网络问题比较复杂,得后续排查链路和交换机。


场景五:DNS 解析突然失效,域名解析不到正确地址。

浏览器报找不到网站,先用dig查一下:

$ 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

echo "203.0.113.23 myservice.example.com" | sudo tee -a /etc/hosts

再试下ping:

$ ping -c1 myservice.example.com
PING myservice.example.com (203.0.113.23)

后续要注意DNS TTL的设置,避免缓存问题。


场景六:HTTPS证书过期,用户浏览器报安全警告。

这个比较尴尬,先查证书有效期:

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:

sudo cp cert.pem /etc/nginx/ssl/mysite.crt
sudo cp key.pem /etc/nginx/ssl/mysite.key
sudo systemctl reload nginx

确认证书正常:

$ curl -sS -o /dev/null -w "%{ssl_verify_result}\n" https://mysite.example.com
0

后面建议自动续期和提前预警。


场景七:数据库连接拒绝,或者主从切换失败。

应用报连接失败,先看看数据库进程:

sudo systemctl status mysqld --no-pager
● mysqld.service - MariaDB database server
   Active: inactive (dead) since Tue 2025-08-10 10:05:12

查看日志看看具体原因:

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

如果主库挂了,赶紧看看有没有从库能顶上去:

$ mysql -uroot -p -e "STOP SLAVE; RESET SLAVE ALL;"

然后把流量切过去。确认3306端口监听:

$ ss -ltnp | grep 3306
LISTEN 0    128    0.0.0.0:3306    0.0.0.0:*    users:(("mysqld",pid=4567,fd=10))

mysqladmin ping确认数据库活着:

$ mysqladmin -uroot -p ping
mysqld is alive

后续别忘了确保复制关系正常,自动故障转移配置好。


场景八:负载均衡后端全都挂了,流量被拒绝。

检查LB后端健康状态:

$ curl -sS http://127.0.0.1:8404; echo
# 看到 backend myapp-server1 DOWN check failed

如果是误判,临时手动把节点标为健康:

echo "enable server mybackend/myserver1" | socat stdio /var/run/haproxy.sock

如果后端真挂了,先下线故障节点,逐个恢复验证。

确认健康接口返回正常:

$ curl -I https://myapp.example.com/health
HTTP/1.1 200 OK

建议改进健康检查逻辑,别只看单个点。


场景九:Kubernetes Pod一直CrashLoopBackOff或者被OOMKilled。

Pod频繁重启,先查Pod状态:

$ kubectl get pods -n prod -o wide
NAME                         READY   STATUS             RESTARTS   AGE
myapp-5d9c6fcb6f-abcde      0/1     CrashLoopBackOff   36         2h

详细事件看看:

$ kubectl describe pod myapp-5d9c6fcb6f-abcde -n prod
Events:
  Warning  BackOff  3m (x5 over 10m)  kubelet  Back-off restarting failed container

查日志:

$ kubectl logs myapp-5d9c6fcb6f-abcde -n prod --previous
panic: runtime error: invalid memory address

如果不急着修代码,先回滚版本或者扩容分摊压力:

$ kubectl rollout undo deployment/myapp -n prod
$ kubectl scale deployment myapp --replicas=5 -n prod

确认Pod恢复:

$ kubectl get pods -n prod
NAME                         READY   STATUS    RESTARTS   AGE
myapp-5d9c6fcb6f-xyz        1/1     Running   0          2m

后续需要收集更多诊断信息,优化资源请求。


场景十:新版本部署失败,引发大面积故障,急需回滚。

观察到错误率飙升,第一时间暂停流水线:

$ curl -X POST -u admin:token "https://ci.example.com/api/v4/projects/1/pipelines/pause"

看版本历史:

$ kubectl rollout history deployment/myapp -n prod
REVISION  CHANGE-CAUSE
1         Initial deploy
2         Broken version

回滚到稳定版本:

$ kubectl rollout undo deployment/myapp --to-revision=1 -n prod
deployment.apps/myapp rolled back

确认恢复:

$ kubectl get deploy myapp -n prod
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
myapp  5/5     5            5           15m

以后要用蓝绿、金丝雀部署,避免上线直接断层。


场景十一:日志系统写入失败或者集中存储宕机。

日志写不进去了,先看看日志代理状态:

$ systemctl status fluentd
● fluentd.service - fluentd
   Active: failed (Result: exit-code) since Tue 10:40

日志里面查原因:

sudo tail -n 50 /var/log/fluentd/fluentd.log
Error: failed to push to ES: connection refused

暂时改成写本地日志,待后续同步:

sudo systemctl restart fluentd

确认本地日志还在流:

tail -n 10 /var/log/myapp/app.log
[2025-08-10T10:50:11Z] INFO request /api/health 200

长远来看,要设计好缓冲和重试机制,避免单点堵塞。


场景十二:数据丢失,需要从备份快速恢复。

有备份才能快恢复,假设MySQL库备份在S3:

$ aws s3 cp s3://backups/mysql/prod_db_2025-08-10.sql.gz /tmp/
$ gunzip /tmp/prod_db_2025-08-10.sql.gz

恢复到备用库,别直接覆盖生产:

$ mysql -uroot -p -e "CREATE DATABASE prod_db_restore;"
$ mysql -uroot -p prod_db_restore < /tmp/prod_db_2025-08-10.sql

确认数据完好,再切流量。

etcd恢复更复杂,必须在维护窗口操作,示例:

$ 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

每次应急结束,别忘了写记录,至少包括事件时间、影响、应急操作、验证结果和后续计划。只有这样,下次遇到类似状况才能更从容。

日常多练多演练,确保流程熟悉。别忘了,自动化和监控是最好的防线,能让你第一时间发现和定位问题。

 
 
发表评论
网名:
评论:
验证:
共有0人对本文发表评论查看所有评论(网友评论仅供表达个人看法,并不表明本站同意其观点或证实其描述)
关注热点事件,尊重事实,追求公正,维护舆论的公正和公信力
关于我们 - 联系我们 - 广告合作 - 关于版权 - 网站地图 - 人才招聘 - 隐私条款 - 免责申明 - 信息举报 - RSS订阅 - 电子公告