故障上报时间
1月3号下午3点10分
原因
应用程序socket使用量累计过多,导致141服务器socket请求数超过linux服务器限制,导致浏览器连接不上。
分析过程
先对事故时间段的生产环境域日志、应用日志、应用监控日志进行检查,其中socket属于操作系统管理资源,不在应用监控范围内。而宕机后重启,由于socket属于可回收资源也随即被释放,因此无法监控那些socket,只能先尝试在测试环境复盘推理出大致问题,再监控生产环境行为,因为环境不同,可能有不一样的结果。
生产环境分析
首先
查找141的AdminServer.000169文件,首次出现如下,表示socket请求拒绝,其中 表示严重的错误消息,此处直指根本问题。
####<2023-1-3 下午03时10分04秒 CST> <DynamicListenThread[Default[2]]> <> <> <> <1672729804826> <Failed to listen on channel “Default[2]” on 192.168.101.141:9001, failure count: 1, failing for 0 seconds, java.io.IOException: 打开的文件过多>。
其次
也检查了2:40-3:10时间段的系统运行情况,总体来说正常。包括如下内容
CPU最高50%;
与142 service交互最长时间11秒;
请求SMS-FWKW/action.do检查最长耗时11秒;
最长SQL执行时间4秒;
最后
也检查了141服务器的socket限制,为6.3W。通过同事了解到上次重启时 间有半月,也就是半月产生了6.3W的socket创建请求,“socket设置过小”这种假设
不合理,更多的像是使用不合理导致。
复盘
在测试环境调整socket连接,刚开始调整为2048,WEB启动直接报错(与生产日志错误相同),后调整为4096系统能正常启动和使用。通过观察/proc/pid/fd可发现socket产生的时间和socket编号,通过”nohup strace -t -e trace=network -f -o output.log -p 21781 2>&1 &”命令产生内核日志output.log,我们能发现socket使用时间、创建时间、复用情况。再结合nohup.out应用启动日志中的业务行为企图发现在某个时刻某些业务行为导致了socket产生。经过多次对比fd目录时间数据和业务行为不完全对上,不能说明问题。最后使用脚本统计内核日志output.log,尝试发现哪些服务使用了开了多少本地端口,本地端口越多,可能性越大。
首先,我们监控了2个小时的测试环境,端口统计及优化建议如下:
访问端口21开了本地端口数量为11(远程连接,不必优化)
访问端口9001开了本地端口数量为49(前台调用后台(包括工作流的其他业务(在报错日志中找出这些业务)),改为连接池)
访问端口53开了本地端口数量为124(DNS域名解析,程序方面不可优化)
访问端口6001开了本地端口数量为2(集团账户管理调用EBS)
访问端口10019开了本地端口数量为55(定时任务EDP,改为连接池)
访问端口26999开了本地端口数量为250(定时任务更新前置机状态CurrentRunningStateJob)
通过以上发现,CurrentRunningStateJob为最可疑,DNS域名解析次之,其他服务使用较少,不做进一步分析。通过深入分析,开本地端口的线程跟26999是同一个,而从outout.log日志发下基本每次开26999端口前都要开53,这与“每次与前置机建立socket,建立socket客户端服务器双方除了交换IP和端口、也会传域名,域名只能通过IP进行反向域名解析”这一理论吻合。
其次,监控了2个小时的生产环境,端口统计如下:
访问端口0开了本地端口数量为27
访问端口8081开了本地端口数量为97
访问端口1521开了本地端口数量为37
访问端口9002开了本地端口数量为68
访问端口9001开了本地端口数量为128(工作流待办)
访问端口21开了本地端口数量为9
访问端口8090开了本地端口数量为2
访问端口26999开了本地端口数量为465(定时任务更新前置机状态CurrentRunningStateJob)
访问端口7001开了本地端口数量为8
通过以上发现,CurrentRunningStateJob为最可疑,跟测试不一样没有DNS网络请求(可能有缓存),CurrentRunningStateJob依旧是首要问题,也应优化工作流待办连接池。
最后,过2个小时再提取生产环境数据,端口统计如下:
访问端口0开了本地端口数量为44
访问端口8081开了本地端口数量为174(edc定时EdcQuartzScheduler_Worker-2)
访问端口26999开了本地端口数量为868(定时任务更新前置机状态CurrentRunningStateJob)
访问端口7001开了本地端口数量为32
访问端口8600开了本地端口数量为2
访问端口1521开了本地端口数量为60
访问端口9002开了本地端口数量为90
访问端口9001开了本地端口数量为232(工作流待办)
访问端口21开了本地端口数量为20
访问端口8090开了本地端口数量为2
访问端口10001开了本地端口数量为17
通过以上发现,CurrentRunningStateJob为最优先、也应优化工作流待办、EDC定时任务连接池。
结论
socket资源由本地IP、本地端口,对方IP、对方端口四要素组成,socket由操作系统负责创建和销毁。当应用程序创建http连接的时候,会创建socket。每次创建socket时,会使用计数器创建唯一编号,进程的最大编号在/proc/pid/limits查看,linux7可在“/etc/security/limits.d/20-nproc.conf”设置、linux5、6可在“/etc/security/limits.conf”设置。当计数器超过限制时会报“文件数过多”类似错误。
在生产中,应采用复用连接技术以减少连接的创建。
优化建议
首先,CurrentRunningStateJob连接的前置机数量有限,应使用缓存机制保存连接。除此之外,如果某个前置机端口一直报错,也应从数据库删除配置,因为过多的连接不上,会浪费本地端口;
其次,工作流待办查询(包括首页右上角查询和工作流模块查询)、EDC定时任务连接池都使用了SimpleHttpInvokerRequestExecutor,而应改成CommonsHttpInvokerRequestExecutor;
最后,目前6.3W的限制数暂不用改,应定期观察长期运行的进程/proc/pid/fd 最大值如果在使用合理的情况下,则需要调整限制数为40W,如果不合理,则进一步调整程序。
标签:socket,端口,CurrentRunningStateJob,访问,本地,JMC,数量 From: https://blog.csdn.net/trtrtg/article/details/141233898