druid使用入坑记(链接缓慢,hold问题)

2024-05-27 06:58

本文主要是介绍druid使用入坑记(链接缓慢,hold问题),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        在工作中,出现使用Druid链接Postgresql数据库,当第一次动态链接数据库源或者连过长时间不使用数据库时,出现链接过程缓慢,甚至hold的情况,链接时间以分计算,导致前端接口响应缓慢,影响用户操作问题。

        经过日志的排查,发现是在DruidDataSource对象链接数据源过程中卡主了,并不是执行SQL语句查询慢的原因,通过网上查询资料,从一下几方面进行改进和问题排查。

        1、是否存在数据源配置文件链接URL地址,host配置问题

        2、是否可以通过修改数据源存活时间或者使用定时心跳保证链接长时间存活

        3、是否能够通过数据源配置文件链接其他参数进行配置,避免该问题

        4、需要通过Druid框架源码分析问题的主要原因,可能更Linux系统、防火墙、数据库服务相关参数存在一定的关系。

        通过Druid社区翻阅相关帖子,发现了和我相同问题的帖子,https://www.oschina.net/question/1450045_2157629?sort=time

帖子中通过程序日志和druid的统计日志进行分析锁定问题在获取链接时或者进行testWhileIdle空闲检验过程中。更多参考文章

https://blog.csdn.net/aiyo92/article/details/86540647

https://www.oschina.net/question/1450045_2157629?sort=time
https://www.oschina.net/question/1450045_2157160
https://my.oschina.net/u/3434392/blog/3017866
https://www.oschina.net/question/2433836_2148757
https://www.oschina.net/question/1034044_2162691?sort=default
https://my.oschina.net/u/3434392/blog/3017866

最后发现是socketTimeout的参数设置的问题,可以通过linux服务器设置,数据源链接也可以设置

jdbc timeout类别

主要有如下几个类别

 

  • transaction timeout 设置的是一个事务的执行时间,里头可能包含多个statement
  • statement timeout(也相当于result set fetch timeout) 设置的是一个statement的执行超时时间,即driver等待statement执行完成,接收到数据的超时时间(注意statement的timeout不是整个查询的timeout,只是statement执行完成并拉取fetchSize数据返回的超时,之后resultSet的next在必要的时候还会触发fetch数据,每次fetch的超时时间是单独算的,默认也是以statement设置的timeout为准)
  • jdbc socket timeout 设置的是jdbc I/O socket read and write operations的超时时间,防止因网络问题或数据库问题,导致driver一直阻塞等待。(建议比statement timeout的时间长)
  • os socket timeout 这个是操作系统级别的socket设置(如果jdbc socket timeout没有设置,而os级别的socket timeout有设置,则使用系统的socket timeout值)。

上面的不同级别的timeout越往下优先级越高,也就是说如果下面的配置比上面的配置值小的话,则会优先触发timeout,那么相当于上面的配置值就”失效”了。

jdbc socket timeout

 

这个不同数据的jdbc driver实现不一样

mysql

jdbc:mysql://localhost:3306/ag_admin?useUnicode=true&characterEncoding=UTF8&connectTimeout=60000&socketTimeout=60000

通过url参数传递即可

pg

jdbc:postgresql://localhost/test?user=fred&password=secret&&connectTimeout=60&socketTimeout=60

pg也是通过url传递,不过它的单位与mysql不同,mysql是毫秒,而pg是秒

oracle

oracle需要通过oracle.jdbc.ReadTimeout参数来设置,连接超时参数是oracle.net.CONNECT_TIMEOUT

  • 通过properties设置 Class.forName("oracle.jdbc.driver.OracleDriver"); Properties props = new Properties() ; props.put( "user" , "test_schema") ; props.put( "password" , "pwd") ; props.put( "oracle.net.CONNECT_TIMEOUT" , "10000000") ; props.put( "oracle.jdbc.ReadTimeout" , "2000" ) ; Connection conn = DriverManager.getConnection( "jdbc:oracle:thin:@10.0.1.9:1521:orcl" , props ) ;
  • 通过环境变量设置 String readTimeout = "10000"; // ms System.setProperty("oracle.jdbc.ReadTimeout", readTimeout); Class.forName("oracle.jdbc.OracleDriver"); Connection conn = DriverManager.getConnection(jdbcUrl, user, pwd); 注意需要在connection连接之前设置环境变量
  • tomcat jdbc pool 一般我们不直接使用jdbc connection,而是使用连接池。由于tomcat jdbc pool是springboot默认使用的数据库连接池,这里就讲述一下如何在tomcat jdbc pool下设置。 spring.datasource.tomcat.connectionProperties=oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000 注意,这里是分号分隔,单位是毫秒,这里可以根据各自的情况配置前缀(tomcat jdbc连接池的话,默认是spring.datasource.tomcat),可以自定义,比如 @Bean @Qualifier("writeDataSource") @ConfigurationProperties(prefix = "spring.datasource.write") public DataSource writeDataSource() { return DataSourceBuilder.create().build(); } 假设你这里是自定义了prefix为spring.datasource.write,那么上述配置就变为 spring.datasource.write.connectionProperties=oracle.net.CONNECT_TIMEOUT=10000;oracle.jdbc.ReadTimeout=60000 oracle.jdbc.ReadTimeout如果没有设置的话,driver里头默认是0

oracle.jdbc.ReadTimeout

driver内部将该值设置到oracle.net.READ_TIMEOUT变量上

  • oracle.net.nt.TcpNTAdapter
    @Overridepublic void setReadTimeoutIfRequired(final Properties properties) throws IOException, NetException {String s = ((Hashtable<K, String>)properties).get("oracle.net.READ_TIMEOUT");if (s == null) {s = "0";}this.setOption(3, s);}public void setOption(int var1, Object var2) throws IOException, NetException {String var3;switch(var1) {case 0:var3 = (String)var2;this.socket.setTcpNoDelay(var3.equals("YES"));break;case 1:var3 = (String)var2;if(var3.equals("YES")) {this.socket.setKeepAlive(true);}case 2:default:break;case 3:this.sockTimeout = Integer.parseInt((String)var2);this.socket.setSoTimeout(this.sockTimeout);}}

可用看到最后设置的是socket的soTimeout

实例

    @Testpublic void testReadTimeout() throws SQLException {Connection connection = dataSource.getConnection();String sql = "select * from demo_table";PreparedStatement pstmt;try {pstmt = (PreparedStatement)connection.prepareStatement(sql);ResultSet rs = pstmt.executeQuery();int col = rs.getMetaData().getColumnCount();System.out.println("============================");while (rs.next()) {for (int i = 1; i <= col; i++) {System.out.print(rs.getObject(i));}System.out.println("");}System.out.println("============================");} catch (SQLException e) {e.printStackTrace();}}

超时错误输出

//部分数据输出
java.sql.SQLRecoverableException: IO 错误: Socket read timed outat oracle.jdbc.driver.T4CPreparedStatement.fetch(T4CPreparedStatement.java:1128)at oracle.jdbc.driver.OracleResultSetImpl.close_or_fetch_from_next(OracleResultSetImpl.java:373)at oracle.jdbc.driver.OracleResultSetImpl.next(OracleResultSetImpl.java:277)at com.example.demo.DemoApplicationTests.testReadTimeout(DemoApplicationTests.java:68)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:497)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)at org.junit.runners.ParentRunner.run(ParentRunner.java:363)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:497)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: oracle.net.ns.NetException: Socket read timed outat oracle.net.ns.Packet.receive(Packet.java:339)at oracle.net.ns.DataPacket.receive(DataPacket.java:106)at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:315)at oracle.net.ns.NetInputStream.read(NetInputStream.java:260)at oracle.net.ns.NetInputStream.read(NetInputStream.java:185)at oracle.net.ns.NetInputStream.read(NetInputStream.java:102)at oracle.jdbc.driver.T4CSocketInputStreamWrapper.readNextPacket(T4CSocketInputStreamWrapper.java:124)at oracle.jdbc.driver.T4CSocketInputStreamWrapper.read(T4CSocketInputStreamWrapper.java:80)at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1137)at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:290)at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192)at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:207)at oracle.jdbc.driver.T4CPreparedStatement.fetch(T4CPreparedStatement.java:1119)... 35 more

刚开始会有数据输出,但是到了某个resultSet的next的时候,报了超时(close_or_fetch_from_next),这个超时指定的是当result.next方法触发新的一批数据的拉取(当一个fetchSize的数据消费完之后,接下来的next会触发新一批数据的fetch)之后在timeout时间返回内没有收到数据库返回的数据。 oracle的jdbc默认的fetchSize为10,也就是每个fetch,如果超过指定时间没接收到数据,则抛出timeout异常。

小结

jdbc的socketTimeout值的设置要非常小心,不同数据库的jdbc driver设置不一样,特别是使用不同连接池的话,设置也可能不尽相同。对于严重依赖数据库操作的服务来说,非常有必要设置这个值,否则万一网络或数据库异常,会导致服务线程一直阻塞在java.net.SocketInputStream.socketRead0。

  • 如果查询数据多,则会导致该线程持有的data list不能释放,相当于内存泄露,最后导致OOM
  • 如果请求数据库操作很多且阻塞住了,会导致服务器可用的woker线程变少,严重则会导致服务不可用,nginx报504 Gateway Timeout

doc

  • oracle.jdbc.ReadTimeout
  • 深入理解JDBC的超时设置
  • 在Spring中基于JDBC进行数据访问时如何控制超时
  • BugFix-HttpURLConnection

这篇关于druid使用入坑记(链接缓慢,hold问题)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1006766

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]