Linux上一个客户端程序不断的尝试连接数据库。如果数据库需要停一下,比如:升级。结果发现启动报错,启动不起来了。
看启动命令的报错,信息很少。开始看mysql的/var/log/db/error.log,发现时间不对,以为是历史日志。感谢曹大帮忙,确认错误日志是启动时产生的,可能是时区设置导致时间不对。进而判断出是端口被占用导致的。
但没有进程回占用数据库进程的监听端口啊?经排查发现了下面的这个奇葩连接。
# netstat -na | grep xxxx
tcp 0 0 127.0.0.1:XXXX127.0.0.1:XXXXESTABLISHED
细想一下,这个自环连接怎么建立起来的哪?源IP:端口等于目的IP:端口。没有人监听在这个端口,竟然因为源端口是这个端口,就连上了?谁发的sys/ack报文?
经确认,还真是这样。在Linux上,不断的尝试连接一个没有开的端口,比如1234,经过几千次尝试,如果碰巧源端口也是1234,就建立了连接。
比如运行下面的脚本:
while true
do
telnet 127.0.0.1 1234
done
尝试一会儿就会显示,连上了。你可以自己和自己聊天了。
…
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
# netstat -na | grep 1234
tcp 0 0 127.0.0.1:1234127.0.0.1:1234ESTABLISHED
Mac上据说做了源/目的端口一致的判断,避免了这种问题。
规避方法之一是修改本地随机端口的选择范围。缺省是1024,改到更高的端口,避开你常用的端口。
# cat /proc/sys/net/ipv4/ip_local_port_range
# echo “1235 65000" > /proc/sys/net/ipv4/ip_local_port_range
另一种方法,设置socket的读超时。虽然连接能很诡异的建立起来,但这个socket是读不出来数据的。读取超时后,断开连接即可。
领取专属 10元无门槛券
私享最新 技术干货