今天定位了一个问题,记录一下
前景
一个Java的Springboot进程,写了一个shell脚本启动,发现启动后,再次重启,怎么都起不来,查看报错是rmi端口被占用
java.rmi.server.ExportException: Port already in use: 0
但是端口被占用的是0啊,这是不可能会被占用的,因此排除被占用的场景。
通过netstat -a查看,大量的mysql的请求处于TIME_WAIT状态,同时也查看到了具体的我们的内部业务的进程,是go业务进程占用的。
此时也刚好得知同时报错,具体是
192.168.51.105:3306: connect cannot assign requested address
bind:An operation and socket counld not be perfirmed because the system I acked sufficient buffer space or because a queue was full。
我分析应该是go内部的连接数据代码大量建立连接导致的,go业务在每1-2秒界面不断的发送查询请求。
刚好也我开发了个监控系统,监控到mysql的状态连接connections不断增加,确实如此。
结果分析:
综合以上得知错误的原因:Linux分配的客户端连接端口用完,导致无法建立socket连接导致。因此虽然socket正常关闭,但是端口不是立即关闭的,而是处于TIME_WAIT状态,需要等待60s才能释放。
事故的原因很明显,go业务代码在不断的建立连接,走读代码发现果然是,同事引用的框架,默认的初始化空闲连接是0,最大连接数竟然是20000。
这简直太疯狂了,截止目前原因已经找到,建议根据业务的规模,配置初始化10个连接,最大连接100个。
引发的思考:
1.如果我们的业务确实需要大量的短暂的连接,我们需要怎么处理?
其实很简单,就是吧linux的socket的等待关闭时间缩减,缩减到我们的正常业务时间。
2.连接池的重要性,这让我们学会,必须配置适当的连接池,否则会造成一些灾难。