公司一个项目的生产环境的JAVA后端应用经常无故长时间卡住,现场排查人员没有保留更多的堆栈信息,所以只能从侧面进行分析。由于该系统的业务量不大,应用经常空闲,所以初步认为不是资源竞争引起的。应用日志中发现从Druid连接池中获取数据库连接时间长达15分钟,基本可以将问题范围缩小到数据库连接获取的环节上。
由于前期其他项目中发生过类似的数据库访问卡顿问题,基本都是网络环境引起的,基本都是远端将socket连接进行了移除,而客户端原因没有得到通知。在数据库交互的环节中可能将连接移除的主体可能是数据库也可能是防火墙。有些环境的防火墙会对超过指定时间的socket连接进行清理,会导致长连接如果长时间没有交互后再次发生交互时长时间卡死。
从度娘查询了下,也有人碰到类似的问题“连接池 执行SQL超时15分钟”https://blog.youkuaiyun.com/u014155356/article/details/82865451,之所以超时时间都是15分钟,是源于操作系统的TCP重试机制。
解决这个问题可以从几个角度入手。
方案一:关闭应用与数据库之间的防火墙,或者延长防火墙对超时socket会话的判定时间。
方案二:数据库启用连接保持。数据库启用连接保持对数据库性能有少许影响。
方案三:应用主机修改系统的默认tcp连接保持,linux系统tcp_keepalive_time参数默认值为7200。建议发生问题的环境可修改为1800,针对连接空闲半小时以上时自动发送keepalive数据包。(该方案需socket操作时指定参数SO_KEEPALIVE,由于JDBC底层不会传