现象
- 给两台服务器配置一台nginx用于负载均衡高可用,但是通过nginx请求数据的时候,发现每次打到第一台的时候,报错,第二台没问题(通过分别反向代理发现哪一台有问题的)。
- 但是,单独去调用每一台服务器的接口,都可以正常拿到数据。
排查过程
- 【第一步:看看是不是网络问题】
- 通过在nginx上ping和telnet port看看网络和端口通不通,看一下两台服务和nginx的防火墙是否都开通。
- 结果都是通的。
- 【第二步:查看是否是机器原因】
- 将负载均衡改成单台的反向代理。结果是第一台依旧不可以,第二台没问题。
- 大概率就是跟第一台的某些配置有关系。
- 【第三步:抓包确认数据是否到达,以及差异】
- 通过分别在服务器上安装Wireshark抓包,发现从nginx过来的请求,除了postman的token不一样,其他均一样,但是两台机器的response不同,第一台永远输出error信息,第二台永远输出成功信息。看一下第一台的error信息,大概是和权限认证相关。
- 猜测可能是跟第一台的权限认证相关。
- 【第四步:查看nginx的error.log】
- 没看出什么有用的信息。
- 【第五步:求助公司大佬】
- 推测是不是会话保持的原因,于是修改nginx的配置文件,其中upstream的分配算法修改为ip_hash。
- 之前抓包也发现了通过nginx转发的报文,connection:close,而直接调用的报文的connection=keep-alive,所以有理由怀疑是因为未保持链接造成认证失败。
- 成功解决问题,测试的时候,每次都成功取到数据。
后记
-
五分钟后,在回家的路上,我认为我错了,这个问题并没有解决,因为ip_hash算法是保证同一个ip映射到同一个后端,做会话保持,我测试的时候,是本机,同一个ip,存在侥幸情况,我映射到第二台上,所以每次请求都是成功的。
-
今天继续验证的时候,换了一台机器发送请求,果然失败了,事后诸葛亮一下,发现三个铁证:
- 之前试过单独代理第一台也是不成功的,所以不太可能是会话保持的原因
- 通过nginx转发的时候,两台机器的报文都是connection:close,所以如果是因为会话保持的原因,不可能一台通,一台不通。
- 修改了转发算法为ip_hash后,通过抓包发现,报文依旧是connection:close,并且nginx不能在响应头部添加Keep-Alive,nginx采用的是http1.0协议,因此没有这个可能。关于nginx不负责的会话保持机制,见Nginx会话保持
-
在反复查看报错信息之后,公司大佬建议我把nginx的http转成tcp试试,结果成了,经过反复测试,终于确认这次是真的成功了。
http{
upstream tomcat_pool{
#server tomcat地址:端口号 weight表示权值,权值越大,被分配的几率越大;
server 192.168.80.22:8080 weight=4 max_fails=2 fail_timeout=30s;
server 192.168.80.22:8081 weight=4 max_fails=2 fail_timeout=30s;
}
server {
listen 80;
server_name tomcat_pool;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://tomcat_pool; #转向tomcat处理
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
换成
stream {
upstream rtmp {
server 127.0.0.1:8089; # 这里配置成要访问的地址
server 127.0.0.2:1935;
server 127.0.0.3:1935; #需要代理的端口,在这里我代理一一个RTMP模块的接口1935
}
server {
listen 1935; # 需要监听的端口
proxy_timeout 20s;
proxy_pass rtmp;
}
}
- 注意:需要重新编译nginx,需要加上:–with-stream,然后make & make install。
- 勉强给一个解释:http应该需要会话保持,并且带上认证的token,而通过nginx的tcp转发到后端机器上,由后端机器去建立认证信息,nginx仅仅是转发tcp请求,不在应用层处理信息。
- 排查思路:就是降低nginx的作用,仅仅做转发,那么由http层降级到tcp层。
现象2
- 使用nginx做负载均衡的两台服务器其他服务均可以被访问,唯独某个服务不可以被访问,但是绕过nginx却可以单独访问。
- 解决办法:
- 试过上述方法后,发现时nginx转发的端口被占用了。占用的这个服务起的比较早,所以后续再起服务的时候,忘记了,这个端口叫做8888,大家千万不要使用这一类特殊端口。