热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Druid连接池中出现15分钟延迟,疑似因Socket超时后重新建立连接所致

2019独角兽企业重金招聘Python工程师标准背景在应用端通过mybatis的interceptor自定义Plugin拦截Executor,统计输出sql的执行耗时。今天生

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

背景

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

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

日志分析

 统计发现:

  1. 出现该情况的单量有6笔,集中在特定的2个小时之内,都是查询sql;都发生在1台应用服务器上。
  2. 在这几笔订单卡住的时间内,轮询任务触发又正常查询成功并正确处理成功!
  3. 数据库层面没有慢sql;且数据库实例的指标监控稳定,应用监控除sql耗时监控异常外,其他一切正常。
  4. 日志没有输出error

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

DruidDataSource的testConnectionInternal

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

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

4192dc532196b5fffeabd895aaa8569671e.jpg

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

336cd80a24597f628b00725ad75a50f40c0.jpg

深入理解JDBC的超时设置

应用与数据库间的timeout层级实例:
转帖: 深入理解JDBC的超时设置
003ebeaaa80bf4ed64c392b35b65c53eb4c.jpg

 上层的timeout依赖于下层的timeout,只有下层的timeout无误时,上层的timeout才能确保正常。eg.  当socket timeout出现问题时,上层的statement timeout和transaction timeout都将失效。
 statement timeout 无法处理网络连接失败时的超时,它能做的仅仅是限制statement的操作时间;网络连接失败时的timeout必须交由JDBC来处理;JDBC的socket timeout会受到操作系统socket timeout设置的影响。

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

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

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

  4. JDBC的socket timeout: 
    4f1d56337a021242007a85094505a4dae4e.jpg

    1. 由于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

  5. 操作系统的socket timeout配置

    e8054926db92dc2e95124324238ab5ca436.jpg
     

番外

MySQL JDBC的queryTimeout的一个坑

在该文章中说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内容
24ee94942a0d85b60183fa3ef375252136f.jpg

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查找发现有相似的问题存在:

  1. https://www.oschina.net/question/1450045_2157629
    2401096b4ef6996950a5c7416e74d185200.jpg

  2. https://www.2cto.com/database/201505/402016.html
    462cf537f2187bc42fb26806d6535043ed5.jpg

  3. 在issues中搜索druid的testWhileIdle问题: https://github.com/alibaba/druid/issues/1260
    527135ff795f000ba717178d50ac523d2ed.jpg


转:https://my.oschina.net/u/3434392/blog/3017866



推荐阅读
  • 优化Flask应用的并发处理:解决Mysql连接过多问题
    本文探讨了在Flask应用中通过优化后端架构来应对高并发请求,特别是针对Mysql 'too many connections' 错误的解决方案。我们将介绍如何利用Redis缓存、Gunicorn多进程和Celery异步任务队列来提升系统的性能和稳定性。 ... [详细]
  • 优化SQL Server批量数据插入存储过程的实现
    本文介绍了一种改进的SQL Server存储过程,用于生成批量插入语句。该方法不仅提高了性能,还支持单行和多行模式,适用于SQL Server 2005及以上版本。 ... [详细]
  • 本文详细介绍了优化DB2数据库性能的多种方法,涵盖统计信息更新、缓冲池调整、日志缓冲区配置、应用程序堆大小设置、排序堆参数调整、代理程序管理、锁机制优化、活动应用程序限制、页清除程序配置、I/O服务器数量设定以及编入组提交数调整等方面。通过这些技术手段,可以显著提升数据库的运行效率和响应速度。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 本文探讨了在 SQL Server 中使用 JDBC 插入数据时遇到的问题。通过详细分析代码和数据库配置,提供了解决方案并解释了潜在的原因。 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • 本文介绍如何使用SAS根据输入数据集自动生成并执行SQL查询,其中CASE语句依据另一个数据集中的观测值动态调整。 ... [详细]
  • 本文深入探讨了SQL数据库中常见的面试问题,包括如何获取自增字段的当前值、防止SQL注入的方法、游标的作用与使用、索引的形式及其优缺点,以及事务和存储过程的概念。通过详细的解答和示例,帮助读者更好地理解和应对这些技术问题。 ... [详细]
  • Oracle中NULL、空字符串和空格的处理与区别
    本文探讨了在Oracle数据库中使用NULL、空字符串('')和空格('_')时可能遇到的问题及解决方案。重点解释了它们之间的区别,以及在查询和函数中的行为。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 1.执行sqlsever存储过程,消息:SQLServer阻止了对组件“AdHocDistributedQueries”的STATEMENT“OpenRowsetOpenDatas ... [详细]
  • 本文详细介绍了MySQL数据库中的Bin Log和Redo Log,阐述了它们在日志记录机制、应用场景以及数据恢复方面的区别。通过对比分析,帮助读者更好地理解这两种日志文件的作用和特性。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 在Fedora 31上部署PostgreSQL 12
    本文详细介绍如何在Fedora 31操作系统上安装和配置PostgreSQL 12数据库。包括环境准备、安装步骤、配置优化以及安全设置,确保数据库能够稳定运行并提供高效的性能。 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
author-avatar
手机用户2502895261
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有