记一次Nginx反向代理500的排查记录
今天公司项目遇到一个奇怪的问题,记录一下。
注: 数据已经过脱敏处理,未暴露公司具体的IP等数据。
TLDR; 项目简单介绍
用 Vue + ElementUI 实现的后台项目(以下简称:a-project),不包含 Node 聚合层,前端开发完成后将打包生成的 dist 文件夹上传到服务器的某目录下,由 Nginx 作为 Web 服务器驱动页面。
同时 Nginx 实现了反向代理,隐藏了服务器真实的 IP 地址。
Nginx 默认配置为 /etc/nginx/nginx.conf 文件,摘录如下:
# /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
        location / {
        }
        error_page 404 /404.html;
            location = /40x.html {
        }
        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}  
从上面配置可以获取到以下信息:
- 错误日志存储在 /var/log/nginx/error.log文件中;
- 访问日志存储在 /var/log/nginx/access.log文件中;
- 监听80端口,子站的配置存储在 /etc/nginx/default.d目录下在的*.nginx文件中;
a-project 的 Nginx 配置文件为:/etc/nginx/default.d/project-a.homedo.com.conf,关键信息摘录如下:
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
server
{
    listen 1024;
    server_name a-project.homedo.com;
    index index.html index.htm;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
    root /home/xxxx/projectA;
    location ^~/a-api/{
        add_header 'Access-Control-Allow-Origin' '*';
        proxy_pass https://a-api.homedo.com/;
    }
    # <======= 注:此处 b-api 的转发突然失败
    location ^~/b-api/ {
       add_header 'Access-Control-Allow-Origin' '*';
       proxy_pass http://b-api.homedo.com/;
    }
    
    location ^~/c-api/ {
        add_header 'Access-Control-Allow-Origin' '*';
        proxy_pass http://c-api.homedo.com/;
    }
    # ... 其他配置
}
问题描述
从上面的 Nginx 配置可以看到 project-a 使用到了 a-api、b-api、c-api 三个子域名的接口,测试反馈说项目中某些接口突然报错500,经排查发现:
- http://b-api.homedo.com通过 Swagger 可以正常访问,通过 PostMan 也可以正常访问;
- 访问 http://a-project.homedo.com访问b-api下的接口,集体报错:500;
- 和用户权限无关,所有用户必现;
- 和接口权限无关,所有 b-api下的接口均报错;
排查过程
STEP1
基本锁定问题是 b-api 转发失败,Nginx 错误日志 /var/log/nginx/error.log 为空,Nginx 并没有捕获到这些报错,access.log 也没有有用的信息。
在 project-a 所在服务器 xx.xx.xx.100 访问 http://a-project.homedo.com/areas/all 接口发现报错:

在另一台服务器(xx.xx.xx.200)访问 http://a-project.homedo.com/areas/all 接口发现可以正常拿到结果。
注: 此处正常是因为 xx.xx.xx.200 从未访问过,目标域名未被 DNS 缓存。
STEP2
询问其他同事发现好多项目都遇到了同样的问题,原因是运维改了域名的解析地址。
解决办法:
- 重启服务器
- 清空DNS缓存
问题原因
首先梳理一下访问路径:
- 用户访问了系统,a-project.homedo.com,DNS将域名解析到xx.xx.xx.100;
- a-project.homedo.com调用- a-api.homedo.com时,DNS会解析到服务器- xx.xx.xx.101;
- a-project.homedo.com调用- b-api.homedo.com时,DNS会解析到服务器- xx.xx.xx.102;
- a-project.homedo.com调用- c-api.homedo.com时,DNS会解析到服务器- xx.xx.xx.103;
(也许是因为机器迁移)运维将 b-api.homedo.com 解析地址改动为 xx.xx.xx.202 后,以上第 3 步由于机器缓存了DNS解析记录,所以报错500。
总结
1. 怎么清除 DNS 缓存?
service nscd restart
2. 为什么重启后问题就解决了?
nscd 服务被重启了。
3. 什么是 nscd?
nscd(Name Service Cache Daemon)是一种能够缓存 passwd、group、hosts 的本地缓存服务,分别对应三个源 /etc/passwd、/etc/hosts、/etc/resolv.conf。其最为明显的作用就是加快 DNS 解析速度,在接口调用频繁的内网环境建议开启。
4. 正向代理和反向代理?
- 正向代理隐藏了用户的真实地址;
- 反向代理隐藏了服务器的真实地址;
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号