解决:The proxy server received an invalid response from an upstream server

最近在App上的调用接口时出现下面的错误信息,导致正常页面无法访问。

The proxy server received an invalid response from an upstream server. Sorry for the inconvenience.
Please report this message and include the following information to us.
Thank you very much!

分析报错原因

根据信息提示(代理服务器无法得到正确响应)往下分析报错原因。
首先检查提示错误信息出处,打开站点nginx虚拟目录的配置文件看到如下配置项:

1
2
3
4
5
6
7
8
9
location~. * . * $ {
client_max_body_size 15m;
client_body_buffer_size 256k;
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host;
proxy_set_header X - Forwarded - For $remote_addr;
proxy_pass http: //localhost:8980; }
proxy_next_upstream
...

这个配置指定了nginx在从一个后端主机取数据遇到何种错误时会转到下一个后端主机,里头写上的就是会出现502的所有情况拉,默认是error timeout。

error就是当机、断线之类的,timeout就是读取堵塞超时。找到提示以后我们往下看,看到最后一行的proxy_pass代理位置(需要转发的路径配置),目前写的是localhost:8980,查询端口号得知此端口连接tomcat服务。所以在此判断应该是tomcat连接出错。

然后找到tomcat配置路径(/opt/apache-tomcat-xxxx/conf)中的server.xml文件查询tomcat端口信息,搜索到如下代码:

1
2
3
4
5
6
7
8
9
<Connector port="8980" 
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
compression="on"
compressionMinSize="2048"
noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
/>

在这可以看到http协议中的8980端口,结合上面的nginx反向代理配置信息确定是在连接tomcat时候报错。

使用top命令查看进程,也并未看到相关进程。下面我们在/opt/apache-tomcat-xxxx/bin中通过命令暂停和重启tomcat服务。

1
2
# sh shutdown.sh
# sh startup.sh

在暂停服务器的时候出现错误信息:

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000006f3000000, 1414856704, 0) failed;
error=’Cannot allocate memory’ (errno=12)。

这是JVM抛出的错误,提示内存分配问题。检查到这里突然想到由于业务调整刚对服务器做过调整,内存从4G降到1G,应该是这个原因导致JVM崩溃。

查找解决方法

分析后,考虑再不升级内存的情况下,通过swap添加虚拟内存,尝试重启comcat服务,添加swap步骤如下:

1、通过df -h查看磁盘使用,发现数据盘/dev/xvdb1 使用90%(共100G),清除附件到53%。

2、在/opt/下创建一个swap文件。

1
mkdir swap cd swap sudo dd if=/dev/xvdb1 of=swapfile bs=1024 count=4194304

根据上面命令分配从数据盘分配4G空间给swap。

3、把生成的文件转换成 Swap 文件

1
sudo mkswap swapfile

4、激活 Swap 文件。

1
sudo swapon swapfile

查看 free -m 的结果,说明已经生效。

Swap: 4095,9 ,4086

重启comcat服务器,启动正常。查看接口,正常。

原本以为到这就结束了,40分钟后又出现异常,查看进程JVM崩溃。停止重启服务器没有问题,好吧,继续查看原因。

使用top命令进行资源查看,发现COMMAND(Java)的%MEM在30分钟内从50%到85%,然后崩溃。
分析基本确定还是内存问题,查看JVM和服务器配置得知通常使用的JVM都是32位的,目前的64位的JVM会损失10-20%的性能,从这个点继续出发做两个修改:

1、Tomcat关闭日志catalina.out,

catalina.out文件会越来越大,对系统的稳定造成了一定的影响。

一般在部署Tomcat后,运行久了,catalina.out文件会越来越大,对系统的稳定造成了一定的影响。可通过修改conf/logging.properties日志配置文件来屏蔽掉这部分的日志信息。

1
catalina.org.apache.juli.FileHandler.level = WARNING

将level级别设置成WARNING就可以大量减少日志的输出,当然也可以设置成OFF,直接禁用掉。

一般日志的级别有:

SEVERE (highest value) > WARNING > INFO > CONFIG > FINE > FINER > FINEST (lowest value)

也可以在bin/catalina.sh代码中的修改:

“$CATALINA_BASE”/logs/catalina.out 2>&1 &
改为:
/dev/null 2>&1 &

我使用的是第二种方法,直接代码简单粗暴。

2、修改tomcat为java分配的内存配置

linux下的tomcat:

修改TOMCAT_HOME/bin/catalina.sh

在“echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:

1
JAVA_OPTS="-server -Xms256m -Xmx512m -XX:PermSize=64M -XX:MaxPermSize=128m"
其他说明

1、“m”说明单位是MB,否则默认是KB
2、一般使用物理内存的80%作为堆大小
3、一般把-Xms和-Xmx设为一样大
4、一般把-Xmn设置为-Xmx值的1/4
5、一般将堆的总大小的50%到60%分配给新生成的池

修改完重启comcat服务,top查看,目前运行时间16小时,%MEM维持在65%左右,正常。后续持续跟进。