mysql socket timeout设置_druid socket timeout超时15分钟(转载)

背景

在应用端通过mybatis的interceptor自定义Plugin拦截Executor, 统计输出sql的执行耗时。

今天生产发生一个很奇怪的问题: 莫名其妙卡顿15分钟+,其后正常返回sql正常结果! 使用druid版本是1.0.2。。。。。

日志分析

统计发现:

出现该情况的单量有6笔,集中在特定的2个小时之内,都是查询sql;都发生在1台应用服务器上。

在这几笔订单卡住的时间内,轮询任务触发又正常查询成功并正确处理成功!

数据库层面没有慢sql;且数据库实例的指标监控稳定,应用监控除sql耗时监控异常外,其他一切正常。

日志没有输出error

推测是否是在getConnection过程中出现了等待。但因获取连接时的日志过少找不到具体的原因!

DruidDataSource的testConnectionInternal

网上的类似问题说的原因是Druid在从连接池中获取的连接(代码详见:DruidDataSource的getConnectionDirect),在开启testWhileIdle时,如果活跃时间距离当前比较久,那么将验证该连接是否有效,无效会discardConnection并再次去pool内获取。

这个过程可能被数据库层面的防火墙策略已经关闭该连接,而客户端还傻傻的发sql验证直到超时。。。。

e7653cd56011aa5567c14c877ab44901.png

在该测试连接的方法中有一个查询超时超时时间:validationQueryTimeout。测试中是-1, 执行的是默认时间。。。。这个默认时间没有找到!! (有找到MappedStatementConfig由SqlMapConfiguration的defaultStatementTimeout)

eeff5067682d1dbc42e9d6b1e4b1a0c7.png

深入理解JDBC的超时设置

应用与数据库间的timeout层级实例:

转帖:深入理解JDBC的超时设置

a1220f6355939aef36f7e4ee1d79e206.png

上层的timeout依赖于下层的timeout,只有下层的timeout无误时,上层的timeout才能确保正常。eg.  当socket timeout出现问题时,上层的statement timeout和transaction timeout都将失效。

statement timeout 无法处理网络连接失败时的超时,它能做的仅仅是限制statement的操作时间;网络连接失败时的timeout必须交由JDBC来处理;JDBC的socket timeout会受到操作系统socket timeout设置的影响。

Transaction Timeout: 一般存在于框架(Spring, EJB)或应用级。spring在配置事务切面的时候可以配置timeout。

Statement Timeout: 通过调用JDBC的java.sql.Statement.setQueryTimeout(int timeout) API进行设置。 以myBatis为例,statement timeout的默认值可以通过sql-map-config.xml中的defaultStatementTimeout 属性进行设置。同时,也可以设置sqlmap中select,insert,update标签的timeout属性,从而对不同sql语句的超时时间进行独立的配置。

JDBC的statement timeout:  通过调用Connection的createStatement()方法创建statement来executeQuery时,会注册一个 TimerTask ->CancelTask 用来给Timer -> ConnectionImpl.getCancelTimer()来处理timeout事项:发送 "KILL QUERY” 。 代码详见: StatementImpl 及 ConnectionImpl

JDBC的socket timeout:

53342a77a23597ac8e7b0f5f804a53bf.png

由于TCP/IP的结构原因,socket没有办法探测到网络错误,因此应用也无法主动发现数据库连接断开。如果没有设置socket timeout的话,应用在数据库返回结果前会无期限地等下去,这种连接被称为dead connection。 为了避免dead connections,socket必须要有超时配置。socket timeout可以通过JDBC设置,socket timeout能够避免应用在发生网络错误时产生无休止等待的情况,缩短服务失效的时间。不推荐使用socket timeout来限制statement的执行时长,因此socket timeout的值必须要高于statement timeout,否则,socket timeout将会先生效,这样statement timeout就变得毫无意义,也无法生效。

eg.   jdbc:mysql://xxx.xx.xxx.xxx:3306/database?connectTimeout=60000&socketTimeout=60000

操作系统的socket timeout配置

835e349b9cd8f4ebcf823b30c7bd5f38.png

番外

在该文章中说Statement.setQueryTimeout : 如果设置的超时时间过长,在当大批量的SQL同时执行时,每一个SQL都会创建一个CancelTask对象,虽然很快执行完,且会调用CancelTask.cancel()方法,但是CancelTask方法的源代码仅仅是将自己的状态修改为:CANCELLED,而并不会直接从队列中移除这个对象, 导致OOM。 建议在cancel()后需要purge一下。

解: MySQL Connector Java 5.1.44  版本 的 StatementImpl 已经有了purge; 且 在1.8版本的JDK对Timer的cancel()也增加了移除queue内容

fc04d2e0bcb0a978c2780166b031b694.png

Timer

public int purge() {

int result = 0;

synchronized(queue) {

for (int i = queue.size(); i > 0; i--) {

if (queue.get(i).state == TimerTask.CANCELLED) {

queue.quickRemove(i);

result++;

}

}

if (result != 0)

queue.heapify();

}

return result;

}

}

public void cancel() {

synchronized(queue) {

thread.newTasksMayBeScheduled = false;

queue.clear();

queue.notify(); // In case queue was already empty.

}

}

类似问题

通过网上blog查找发现有相似的问题存在:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值