公司一个项目的生产环境的JAVA后端应用经常无故长时间卡住,现场排查人员没有保留更多的堆栈信息,所以只能从侧面进行分析。由于该系统的业务量不大,应用经常空闲,所以初步认为不是资源竞争引起的。应用日志中发现从Druid连接池中获取数据库连接时间长达15分钟,基本可以将问题范围缩小到数据库连接获取的环节上。
由于前期其他项目中发生过类似的数据库访问卡顿问题,基本都是网络环境引起的,基本都是远端将socket连接进行了移除,而客户端原因没有得到通知。在数据库交互的环节中可能将连接移除的主体可能是数据库也可能是防火墙。有些环境的防火墙会对超过指定时间的socket连接进行清理,会导致长连接如果长时间没有交互后再次发生交互时长时间卡死。
从度娘查询了下,也有人碰到类似的问题“连接池 执行SQL超时15分钟”https://blog.csdn.net/u014155356/article/details/82865451,之所以超时时间都是15分钟,是源于操作系统的TCP重试机制。
解决这个问题可以从几个角度入手。
方案一:关闭应用与数据库之间的防火墙,或者延长防火墙对超时socket会话的判定时间。
方案二:数据库启用连接保持。数据库启用连接保持对数据库性能有少许影响。
方案三:应用主机修改系统的默认tcp连接保持,linux系统tcp_keepalive_time参数默认值为7200。建议发生问题的环境可修改为1800,针对连接空闲半小时以上时自动发送keepalive数据包。(该方案需socket操作时指定参数SO_KEEPALIVE,由于JDBC底层不会传递该参数,所以该方案无效)
方案四:升级数据库连接池。Druid连接池从1.0.28开始,添加了druid.keepAlive属性:https://www.oschina.net/news/81611/druid-1-0-28 ,在该版本下可通过设置druid.keepAlive为true启用连接池自身的连接保持,设置方式可以是构造连接池时的参数也可以是应用启动时的环境变量。而在Druid1.1.5版本中也有对数据库卡顿15分钟问题的解决:https://www.oschina.net/news/90026/druid-1-1-5。
方案五:启用JDBC本身的超时控制机制,在java启动环境变量中加上“-Doracle.net.CONNECT_TIMEOUT=60000 -Doracle.jdbc.ReadTimeout=60000”。这两个参数会导致真正长时间的查询语句也会在超过指定时间没应答时被应用强制中断,需谨慎使用。关于JDBC的超时机制可阅读参考资料:https://www.cubrid.org/blog/understanding-jdbc-internals-and-timeout-configuration
解决数据库连接超时15分钟问题
1094

被折叠的 条评论
为什么被折叠?



