网站出现503 Service Unavailable怎么办?服务状态、负载与Nginx配置排查教程

网站出现503 Service Unavailable怎么办?服务状态、负载与Nginx配置排查教程

访问网站时出现503 Service Unavailable,表示服务器当前无法处理请求,但这种状态通常是暂时性的。它可能来自Nginx、Apache、CDN、负载均衡器、PHP-FPM、Java应用、Node.js服务,也可能是网站进入维护模式后主动返回的结果。

503并不等于服务器一定宕机。服务器仍然可以联网、Nginx也可能正常运行,只是后端服务不可用、请求队列已满、进程池耗尽,或者限流规则拒绝了当前请求。

本文介绍如何判断503由哪一层返回,并使用curlsystemctljournalctlss、Nginx日志和系统资源指标逐步定位故障。示例以常见Linux、Nginx和PHP-FPM环境为主,也适用于反向代理Java、Node.js、Python等应用的场景。

一、503状态码表示什么

HTTP 503表示服务暂时不可用。常见特点包括:

  • 故障可能在短时间后恢复。
  • 服务可能主动进入维护状态。
  • 网关可以访问,但后端应用暂时不能处理请求。
  • 服务器资源或应用并发达到上限。
  • 限流、连接限制或过载保护主动拒绝请求。

部分503响应会携带Retry-After响应头,用于提示客户端稍后重试。但并不是所有503响应都会包含该字段。

503与其他常见状态码的区别:

状态码常见含义优先排查方向
500应用内部处理出错程序异常、依赖、代码和应用日志
502网关收到无效的上游响应上游进程、端口、协议和响应格式
503服务暂时不可用或主动拒绝维护、限流、队列、进程池和过载
504网关等待上游响应超时慢请求、数据库、网络和超时配置

实际系统可能通过自定义配置改变返回状态码,因此最终仍应结合响应头、页面内容和日志判断。

二、先确认503由哪一层返回

在客户端执行:

curl -I https://example.com/

查看完整请求过程:

curl -vk https://example.com/

重点关注:

  • Server响应头。
  • 是否存在CDN或代理相关响应头。
  • 是否包含Retry-After
  • 响应页面是CDN、Nginx、应用还是网站程序的模板。
  • 所有页面都返回503,还是只有动态页面或特定接口异常。

分别测试公网域名和源站:

curl -I https://example.com/
curl -I http://127.0.0.1/ -H 'Host: example.com'

如果源站正常而公网域名返回503,重点检查CDN、负载均衡、WAF和回源配置。

如果源站本机也返回503,继续检查Nginx规则和后端应用。

如果只有某个接口返回503,问题更可能位于该接口对应的应用、依赖服务或局部限流规则。

三、保存故障现场再重启服务

遇到503时,不建议第一步就重启服务器。重启可能暂时恢复服务,却会清除进程、连接队列和部分日志现场,使真正原因无法定位。

先记录时间和基础状态:

date
uptime
free -h
df -h
df -i
vmstat 1 5

查看资源占用较高的进程:

ps -eo pid,ppid,user,%cpu,%mem,rss,stat,etime,comm,args \
  --sort=-%cpu | head -n 20

再按内存排序:

ps -eo pid,ppid,user,%cpu,%mem,rss,stat,etime,comm,args \
  --sort=-rss | head -n 20

需要重点确认:

  • 系统负载是否突然升高。
  • 可用内存是否接近耗尽。
  • 是否持续发生Swap换入换出。
  • 磁盘空间或inode是否已满。
  • 应用进程是否消失、反复重启或占满CPU。
  • 是否存在大量不可中断的D状态进程。

四、检查Nginx和后端服务状态

查看Nginx:

sudo systemctl status nginx --no-pager

查看PHP-FPM。具体服务名取决于系统和PHP版本:

systemctl list-units --type=service | grep -E 'php.*fpm'

例如:

sudo systemctl status php8.3-fpm --no-pager

如果是其他应用:

sudo systemctl status myapp.service --no-pager

查看最近日志:

sudo journalctl -u nginx --since '30 minutes ago' --no-pager
sudo journalctl -u php8.3-fpm --since '30 minutes ago' --no-pager
sudo journalctl -u myapp.service --since '30 minutes ago' --no-pager

常见异常包括:

  • 服务启动失败或退出。
  • 配置文件语法错误。
  • 端口被占用。
  • 内存不足被系统终止。
  • 应用依赖连接失败。
  • 进程达到最大并发。
  • systemd因连续失败限制重启。

五、检查Nginx错误日志和访问日志

常见日志位置:

sudo tail -n 200 /var/log/nginx/error.log
sudo tail -n 200 /var/log/nginx/access.log

实时观察:

sudo tail -f /var/log/nginx/error.log

筛选503:

sudo awk '$9 == 503 {print}' /var/log/nginx/access.log | tail -n 100

如果使用自定义日志格式,状态码所在字段可能不是第9列,更可靠的方法是根据实际log_format解析。

排查时关注:

  • 503是否集中在某个URI。
  • 是否集中在某些来源IP。
  • 是否突然出现流量高峰。
  • 503前后是否伴随502或504。
  • 错误日志是否出现连接失败、共享内存不足或限流提示。
  • 故障是否与发布、备份、定时任务或爬虫访问时间重合。

六、确认上游端口或Unix Socket是否可用

查看监听端口:

sudo ss -lntp

检查指定端口:

sudo ss -lntp | grep ':9000 '

测试HTTP上游:

curl -v http://127.0.0.1:8080/health

测试TCP端口:

nc -vz -w 3 127.0.0.1 8080

如果PHP-FPM使用Unix Socket:

sudo ls -l /run/php/

需要确认:

  • Nginx配置的端口与应用实际监听端口一致。
  • Socket文件确实存在。
  • Nginx工作进程用户有权访问Socket。
  • 应用没有只监听错误的地址。
  • 容器端口和宿主机映射正确。
  • 应用重启后Socket路径没有变化。

查看Nginx最终配置:

sudo nginx -T

只做语法检查:

sudo nginx -t

修改配置后应先执行nginx -t,确认成功再重新加载:

sudo systemctl reload nginx

七、Nginx限流可能主动返回503

Nginx的limit_req模块用于限制请求速率。请求超过限制并被拒绝时,默认状态码可以是503。

检查配置:

sudo nginx -T | grep -nE 'limit_req|limit_req_zone|limit_req_status'

示例:

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

server {
    location /api/ {
        limit_req zone=api_limit burst=20 nodelay;
    }
}

如果用户正常访问也频繁触发503,需要判断:

  • 限制维度是否合理。
  • CDN或反向代理后是否把所有访客识别成同一个IP。
  • burst是否过小。
  • 接口是否存在前端重复请求。
  • 爬虫或攻击流量是否集中。
  • 日志中是否存在限流拒绝信息。

可以显式把限流状态码改为429,使“请求过多”与“服务不可用”更容易区分:

limit_req_status 429;

不要为了消除503直接删除全部限流。应先识别真实客户端IP,修正阈值,并确认应用能够承受放宽后的并发。

八、检查连接数限制和文件描述符

查看Nginx连接相关配置:

sudo nginx -T | grep -nE 'worker_connections|worker_rlimit_nofile|limit_conn'

查看进程限制:

pid=$(cat /run/nginx.pid)
cat /proc/$pid/limits

查看系统文件描述符:

cat /proc/sys/fs/file-nr

查看某个服务当前打开的文件:

sudo ls /proc/$(pgrep -o nginx)/fd | wc -l

当进程或系统达到文件描述符上限时,可能无法接受新连接、打开日志、连接Socket或读取文件。

不要只修改worker_connections。实际并发能力还受文件描述符、上游连接、内存、内核队列和应用处理能力影响。

九、PHP-FPM进程池耗尽

WordPress、PHP商城和其他PHP网站出现503时,PHP-FPM进程池耗尽是常见原因之一。

检查日志:

sudo journalctl -u php8.3-fpm --since '30 minutes ago' --no-pager

查看池配置:

grep -R -E '^(pm|pm\.max_children|pm\.start_servers|pm\.min_spare_servers|pm\.max_spare_servers|pm\.max_requests|request_slowlog_timeout|slowlog)' \
  /etc/php/*/fpm/pool.d/

重点参数:

  • pm.max_children:允许同时处理请求的最大子进程数。
  • pm.start_servers:动态模式启动时创建的进程数。
  • pm.min_spare_servers:最少空闲进程数。
  • pm.max_spare_servers:最多空闲进程数。
  • pm.max_requests:子进程处理一定请求后重建,可用于缓解长期内存增长。

如果状态页已安全启用,可关注:

  • listen queue是否持续大于0。
  • idle processes是否长期为0。
  • active processes是否达到总进程数。
  • max children reached是否持续增加。
  • slow requests是否增长。

状态页可能暴露请求URL和资源信息,只能允许本机、内网监控或可信IP访问,不能直接公开到互联网。

不要盲目提高pm.max_children。可以先估算单个PHP-FPM进程的实际内存:

ps --no-headers -o rss -C php-fpm8.3 |
  awk '{sum+=$1; n++} END {if(n) printf "avg=%.1f MB, processes=%d\n",sum/n/1024,n}'

进程数过高会消耗更多内存,严重时触发Swap或OOM,反而让503更加频繁。

十、检查CPU、内存和OOM

查看系统:

uptime
free -h
vmstat 1 10

检查OOM记录:

sudo journalctl -k --since '2 hours ago' |
  grep -iE 'out of memory|oom|killed process'

如果应用被OOM Killer终止,重启应用只能暂时恢复。还应继续确认:

  • 是否存在内存泄漏。
  • 进程并发是否设置过高。
  • 缓存或队列是否无限增长。
  • 是否在同一时间执行备份、压缩或批处理。
  • 容器内存限制是否过低。
  • 系统是否缺少合理的资源余量。

查看容器状态:

docker ps -a
docker stats --no-stream

查看容器退出原因:

docker inspect container_name \
  --format '{{.State.Status}} {{.State.ExitCode}} {{.State.OOMKilled}}'

十一、检查磁盘空间、inode和只读文件系统

应用无法写入会话、缓存、日志、临时文件或数据库时,也可能主动返回503。

检查磁盘:

df -h
df -i

检查文件系统是否只读:

findmnt -no TARGET,OPTIONS /

查看内核存储错误:

sudo journalctl -k --since '2 hours ago' |
  grep -iE 'I/O error|read-only|filesystem|ext4|xfs'

重点检查:

  • /var/tmp、网站目录和数据库目录。
  • inode是否耗尽。
  • 日志是否快速增长。
  • 文件系统是否因错误被重新挂载为只读。
  • 容器可写层是否占满。

不要看到磁盘满就直接删除未知文件。应先使用du或日志工具定位来源,再按服务规则安全清理。

十二、检查数据库、Redis和外部依赖

应用本身运行正常,也可能因为数据库、Redis、消息队列或第三方接口不可用而返回503。

检查常见服务:

sudo systemctl status mysql --no-pager
sudo systemctl status redis-server --no-pager

测试数据库端口:

nc -vz -w 3 127.0.0.1 3306

测试Redis:

redis-cli PING

常见问题包括:

  • 数据库连接数耗尽。
  • SQL慢查询导致应用线程堆积。
  • Redis内存达到上限。
  • DNS解析异常导致外部依赖连接缓慢。
  • 消息队列积压。
  • 第三方接口超时,应用没有做好降级。

应结合应用日志确认503是应用主动返回,还是代理层生成。

十三、WordPress维护模式导致503

WordPress升级核心、主题或插件时,会在站点根目录创建.maintenance文件。升级中断后,该文件可能没有正常删除,使网站持续显示维护状态。

检查:

ls -la /path/to/wordpress/.maintenance

确认当前没有升级任务,并做好备份后再移除:

rm /path/to/wordpress/.maintenance

还应检查:

  • 插件是否主动启用了维护模式。
  • CDN是否缓存了维护页面。
  • PHP错误是否发生在升级之后。
  • 文件权限和依赖是否完整。

不要只删除维护文件就结束排查。如果升级过程失败,应继续确认插件、主题、数据库更新和文件完整性。

十四、CDN、WAF和负载均衡返回503

当源站本机正常,而用户通过域名访问503时,应检查前置网络服务。

常见原因:

  • CDN无法连接源站。
  • 源站IP或回源端口填写错误。
  • 回源协议HTTP与HTTPS不一致。
  • WAF规则误拦截。
  • 负载均衡健康检查失败。
  • 所有后端节点被标记为不可用。
  • CDN边缘节点限流或服务异常。
  • 源站只允许旧的CDN出口IP。

使用curl分别测试:

curl -I https://example.com/
curl -I http://SOURCE_IP/ -H 'Host: example.com'

如果HTTPS源站要求SNI:

curl -vk --resolve example.com:443:SOURCE_IP https://example.com/

这能让请求直接连接指定源站IP,同时保留正确的域名和TLS SNI。

十五、如何安全恢复服务

已经确认故障来源后,可以按以下原则恢复:

服务停止

先查看日志和配置,再启动或重启:

sudo nginx -t
sudo systemctl restart nginx
sudo systemctl restart php8.3-fpm

应用过载

  • 临时限制异常流量。
  • 暂停高消耗定时任务。
  • 对非核心接口降级。
  • 增加健康节点。
  • 修复慢查询和阻塞请求。
  • 在确认内存余量后调整进程池。

磁盘或内存耗尽

  • 先停止异常增长来源。
  • 安全清理明确可删除的数据。
  • 恢复必要的磁盘和内存余量。
  • 再启动受影响服务。

配置错误

  • 使用配置检查命令验证。
  • 回滚到已知可用版本。
  • 重新加载后观察日志。
  • 从本机和公网分别验证。

恢复后执行:

curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com/

并持续观察:

sudo journalctl -u nginx -f

十六、不要用这些方式“解决”503

以下操作可能暂时隐藏问题,但通常会增加后续风险:

  • 不看日志直接重启整台服务器。
  • 无限提高PHP-FPM进程数。
  • 删除全部Nginx限流规则。
  • 把所有防火墙和安全组规则关闭。
  • 只增加代理超时时间。
  • 看到磁盘满就批量删除未知目录。
  • 将状态页直接开放到公网。
  • 在流量高峰直接执行高风险配置变更。

503的根因通常是“服务能力暂时低于请求压力”或“某个必要组件不可用”。真正的修复需要找到具体瓶颈,而不是只让错误页面短暂消失。

十七、建议建立哪些监控

建议持续记录:

  • HTTP 503数量和比例。
  • 按域名、URI、节点和上游拆分的状态码。
  • Nginx活跃连接和请求速率。
  • 上游响应时间和失败次数。
  • PHP-FPM活动进程、空闲进程、等待队列和最大子进程触发次数。
  • 应用线程池、连接池和队列长度。
  • CPU、系统负载、内存、Swap和OOM事件。
  • 磁盘空间、inode和I/O延迟。
  • 数据库连接数、慢查询和锁等待。
  • Redis内存、淘汰数量和连接数。
  • CDN回源状态及负载均衡健康节点数量。

告警不能只看“网站是否能打开”。即使整体可用,某个接口持续503、等待队列增长或空闲进程降为0,也应提前处理。

十八、推荐的完整排查顺序

网站出现503时,可以按下面的顺序操作:

  1. 使用curl -I查看状态码、响应头和返回层级。
  2. 对比公网域名、源站IP和本机访问结果。
  3. 保存故障时间、系统负载、内存、磁盘和进程现场。
  4. 检查Nginx、PHP-FPM或应用服务状态。
  5. 查看Nginx错误日志、访问日志和应用日志。
  6. 使用sscurlnc检查上游端口和Socket。
  7. 使用nginx -T检查限流、连接限制和代理配置。
  8. 确认是否由limit_req主动返回503。
  9. 检查PHP-FPM等待队列和max children reached
  10. 检查CPU、内存、OOM、磁盘和inode。
  11. 检查数据库、Redis和外部依赖。
  12. 检查WordPress维护模式或应用维护开关。
  13. 如果源站正常,检查CDN、WAF和负载均衡。
  14. 修复根因后再有针对性地重启或重新加载服务。
  15. 从内外网络验证恢复,并持续观察日志和监控。

总结

503 Service Unavailable表示当前服务暂时不能处理请求,但返回503的组件可能是CDN、Nginx、限流模块、PHP-FPM、应用程序或维护模式。

排查的核心不是立即重启,而是先确认503由哪一层生成。使用curl对比公网、源站和本机响应,使用systemctljournalctl检查服务,使用ss确认上游监听,再结合Nginx日志、PHP-FPM状态和系统资源定位具体瓶颈。

如果503来自流量高峰,应同时处理异常请求、应用并发、数据库性能和资源容量;如果来自维护或配置错误,应通过配置检查和安全回滚恢复。建立分层状态码、上游延迟、进程池队列和系统资源监控,才能在用户大面积看到503之前发现问题。

知识库

Redis内存占用过高怎么办?内存分析、淘汰策略与安全优化教程

2026-8-12 16:28:09

知识库

Linux服务器时间不准怎么办?Chrony时间同步、时区配置与故障排查教程

2026-8-13 16:57:37