近日,我们的k8s+rancher的docker环境出现了一个很奇怪的问题,在没有进行任何操作的情况下,我们的web跑着跑着就突然挂了。导致我们自动化用例全部执行失败。于是我和罗仔开始了以下的排查过程。
首先就是在我们的web上查看日志,发现没有任何抛错。我们的自动化用例开启后,一直再向服务端发起请求,但是服务端返回给客户端的响应都是异常,说明服务端压根没有收到请求。于是我们check了Nginx的配置,没有问题,那是为什么呢,这时我们打开netstat命令
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
发现服务器有大量的CLOSE_WAIT状态的socket,这时候问题原因找到了,是因为大量的CLOSE_WAIT造成tomcat假死,以至于我们的web无法提供服务。
如下图:
根据tcp四次挥手的状态图可以看出来,这个状态是因为客户端主动发起了关闭socket连接的请求,发送了FIN报文给服务端,此时服务端处于了CLOSE_WAIT状态,但是服务器程序自己没有进一步发出ack 信号,于是导致这个资源一直被程序占着。紧接着我们查询了Nginx的日志,发现出现了大量的499状态码。查看Nginx中499的定义是 “client has closed connection”。说明客户端等的不耐烦了,主动关闭了连接。
于是我们发现,这个时间段内,只有我们获取cookie的微服务在不断地发起http请求,于是我们停止该微服务,观察了一段时间,发现close_wait没有再增长,那么问题的源头就找到了。查看我们微服务的代码发现:
try {
response = HttpUtil.processJsonPost(client
, context
, gotestUrl
, headers,bodyData);
String jsonBody = EntityUtils.toString(response.getEntity(), "UTF-8");
JSONObject responseObj = JSONObject.parseObject(jsonBody);
if (responseObj.getInteger("code")== 200){
logger.log(Level.INFO,"success! ");
}else {
logger.log(Level.WARNING,"something going wrong! ");
}
}catch (Exception ex){
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
代码中的http连接都没有关闭,所以导致出现大量的close_wait。修改代码:
try {
response = HttpUtil.processJsonPost(client
, context
, gotestUrl
, headers,bodyData);
String jsonBody = EntityUtils.toString(response.getEntity(), "UTF-8");
JSONObject responseObj = JSONObject.parseObject(jsonBody);
if (responseObj.getInteger("code")== 200){
logger.log(Level.INFO,"success! already send cookie to gotest");
}else {
logger.log(Level.WARNING,"something going wrong! cannot seccessfully send cookie to gotest");
}
}catch (Exception ex){
logger.log(Level.SEVERE, ex.getMessage(), ex);
}finally {
if (null != client){
try {
client.close();
}catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
if (null != response) {
try {
response.close();
}catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
}
}
重启微服务,果然close_wait没有再增长了,问题解决。
经过这次问题的排查,也给了自己一下警示:
1.代码一定要规范,尤其是在申请资源的部分,写之前就需要注释,不要忘记释放资源;
2.排查问题的时候,需要逐步地去分析,一个一个地排除影响因子,才能更快更准确地定位问题。