服务端口占用案例分析

in 互联网技术 with 0 comment  访问: 3,465 次

背景

因为公司有些私有化业务(TOB),需要到客户现场部署,所以考虑到POC的简单性,我们有较多服务是安装在一台主机上的,所以出现了端口占用导致程序重启不生效的情况。

现象

nginx-upstream.png
环境架构大概如上图所示,在一台主机上,nginx代理了Java Api Server程序,当问题发生时,重启Java API Server程序时提示Address already use,具体信息如下:
port-alerdy-use.png

问题排查过程

既然端口占用了就用netstat -antltp |grep 10003 看看Java API Server启动的服务端口10003被谁,给占用了,详情如下:
port-use-status.png
原来有一个Nginx的ESTABLISHED链接,本想重启Tengine让其释放,但是重启后发现状态变成TIME_WAIT,然后尝试重启Java Api Server还是报错。

分析根因

从上面可以看出10003端口是被nginx占用,这是运维nginx接收了很多请求,进行代理的时候发起tcp连接,这时会占用一个未被使用的随机端口,而后端应用和nginx部署在同一台机器,由于请求过多,nginx发起了大量连接,每个连接都是短连接,占用了大量的随机端口,并且需要经过30秒的TIME_WAIT状态才能释放占用,而这里碰巧nginx随机端口Local Address 也是10003, 跟我们Api Server程序要启动的服务端口10003正好冲突,还没有被释放,这才导致这种情况的发生。

问题解决

我们可以尝试把nginx和java程序分开部署在不同的机器,这个问题自然不会发生,但是这不是根本解决问题,如果根本解决这个问题呢,那就是控制nginx随机端口把我们服务要监听的端口排除,我们只需要修改内核参数net.ipv4.ip_local_port_range

查看端口范围:

sysctl  net.ipv4.ip_local_port_range

临时修改端口范围:

echo 20000 50000 > /proc/sys/net/ipv4/ip_local_port_range

如果是非root用户,加sudo即可。

永久修改端口范围:

sed -i 's#net.ipv4.ip_local_port_range.*#net.ipv4.ip_local_port_range 20000 50000#g' /etc/sysctl.conf
sysctl -p

修改完成后,重启服务看看:
netstat-anltp-port.png
如上图可以看出nginx随机启动的端口已经是在我们设置的范围内。

为何我这里设置为20000 ~ 50000, 这是因为我们有这样的场景,我们私有化部署我们的产品会有很多服务部署在一台机器上,比如hadoop的程序就有50000以上的服务端口,所以你设置按照你的场景设置即可,把你正常程序的监听端口排除掉就好。

WeZan