09. 运维和故障排查

1. 排障原则

遇到“网站打不开”时,从外到内逐层验证:

DNS
  → 云安全组与 UFW
  → Nginx 80/443
  → TLS 证书和虚拟主机
  → Nginx 静态文件或反向代理
  → PM2 / Express 3000
  → MySQL 3306
  → 具体 SQL 和业务代码

每一层都用一个最小命令验证。不要一开始同时重启 Nginx、PM2 和 MySQL,否则会丢失故障现场。

2. DNS 检查

dig +short airport.cxhair.cn A

若 IP 错误:检查 DNS 控制台记录和 TTL。若本地与公共 DNS 结果不同,可以分别查询:

dig @1.1.1.1 airport.cxhair.cn A
dig @8.8.8.8 airport.cxhair.cn A

DNS 正确不代表服务器端口可访问。

3. 网络和监听端口

sudo ss -lntp | grep -E ':80|:443|:3000|:3306'
sudo ufw status verbose

同时检查京东云安全组。理想状态:

从本地电脑测试端口比在服务器内部更能证明公网链路。

4. Nginx 检查

sudo nginx -t
systemctl status nginx --no-pager
sudo journalctl -u nginx -n 100 --no-pager
sudo tail -n 100 /var/log/nginx/airport.error.log
sudo tail -n 100 /var/log/nginx/airport.access.log

输出完整生效配置:

sudo nginx -T

nginx -T 可能很长,可定位:

sudo nginx -T 2>&1 | grep -n "airport.cxhair.cn\|proxy_pass\|ssl_certificate"

5. TLS 检查

sudo certbot certificates
sudo certbot renew --dry-run

检查线上证书:

openssl s_client \
  -connect airport.cxhair.cn:443 \
  -servername airport.cxhair.cn </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

常见问题:

6. PM2 和 Express 检查

pm2 status
pm2 describe airport-api
pm2 logs airport-api --lines 200 --nostream
curl -i http://127.0.0.1:3000/health

如果本机 3000 正常而公网 /health 失败,问题多半在 Nginx 或外层网络。如果本机 3000 失败,先查 PM2 日志和环境变量。

检查进程使用的 Node.js:

node --version
which node
pm2 report

7. MySQL 检查

systemctl status mysql --no-pager
sudo journalctl -u mysql -n 200 --no-pager
mysql -h 127.0.0.1 -u airport_app -p airportdb_training \
  -e "SELECT 1 AS database_ok;"

管理员查看连接:

sudo mysql -e "SHOW FULL PROCESSLIST;"
sudo mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_connected';"

不要看到慢请求就立即重启 MySQL。记录 SQL、绑定参数、数据范围和执行计划,再判断是缺少索引、范围过大、锁等待还是连接池问题。

8. 常见 HTTP 状态

404

502 Bad Gateway

Nginx 无法连接 Express。检查:

pm2 status
curl -i http://127.0.0.1:3000/health
sudo ss -lntp | grep ':3000'

503 Service Unavailable

本项目 /health 在进程可用但数据库 down 时主动返回 503。读取 JSON body,区分 Nginx 自己生成的 503 和 Express 健康检查。

504 Gateway Timeout

Nginx 已连接后端,但在 proxy_read_timeout 内没有得到响应。根据 request ID 查 PM2 日志和慢 SQL。不要先把超时改成无限大。

413 Request Entity Too Large

请求体超过 Nginx 或 Express 限制。本项目是只读查询应用,通常不应上传大文件。先确认业务是否合理,再调整限制。

9. request ID 关联日志

Nginx 将 $request_id 通过 X-Request-ID 传给 Express。API 响应也返回 request_id。发生错误时:

  1. 从浏览器响应获取 request ID;
  2. 在 PM2 日志搜索该 ID;
  3. 在 Nginx access log 定位同一次请求;
  4. 查看路径、状态码、耗时和对应 SQL 日志。

可将 Nginx日志格式扩展为包含 $request_id,例如在 http 块定义:

log_format airport_main
  '$remote_addr - $host [$time_local] "$request" $status $body_bytes_sent '
  'request_id=$request_id request_time=$request_time '
  'upstream_time=$upstream_response_time';

站点使用:

access_log /var/log/nginx/airport.access.log airport_main;

修改 /etc/nginx/nginx.conf 前备份,执行 nginx -t 后再 reload。

10. 容量检查

df -h
df -i
free -h
du -sh ~/.pm2/logs
sudo du -sh /var/log/nginx /var/lib/mysql

磁盘满会导致 MySQL、日志和部署同时失败。需要同时监控磁盘空间和 inode。

11. 定期维护

每周或每月根据项目活跃度执行:

依赖审计结果需要判断可利用路径和升级兼容性,不要在生产服务器直接运行破坏性 npm audit fix --force。

12. 数据库备份边界

AirportDB 可以从官方 dump 重新导入,但索引实验、性能记录和额外应用数据需要单独保存。至少备份:

备份中包含凭据时应加密并限制权限。

下一章:配置模板与检查清单