并发过大druid异常:Thread pool is EXHAUSTED!

在高并发场景下,项目出现了'线程池资源耗尽'的异常。通过jmeter压力测试,发现是Druid连接池配置不当导致。经过分析,调整了线程池大小和Druid的最大连接数,最终将Druid的最大连接数设置为20,成功解决了异常,确保服务稳定运行。

项目源码地址:https://gitee.com/lilyssh/high-concurrency

当并发量太高,就会导致部分请求调用服务失败,我们就需要定位瓶颈在哪里,再对症下药,本篇就是为了说明线程池资源耗尽的情况下该怎么办。

1. 用jmeter压测



2. 异常描述

运行,会看到部分请求失败:

在项目控制台会看到报错信息:threadpool is exhausted,线程池耗尽。

2018-09-14 11:04:30.365 [http-nio-1111-exec-435] ERROR cn.lilyssh.common.exception.ExceptionAdviceHandler  - 处理出现异常
com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method save in the service cn.lilyssh.order.api.service.OrderServiceApi. Tried 3 times of the providers [192.168.31.31:3333] (1/1) from the registry ssh.qianxunclub.com:2181 on the consumer 192.168.31.31 using the dubbo version 2.6.0. Last error is: Failed to invoke remote method: save, provider: dubbo://192.168.31.31:3333/cn.lilyssh.order.api.service.OrderServiceApi?anyhost=true&application=order-consumer&check=false&default.check=false&dubbo=2.6.0&generic=false&interface=cn.lilyssh.order.api.service.OrderServiceApi&methods=save,list&pid=2372&register.ip=192.168.31.31&remote.timestamp=1536893088718&side=consumer&timestamp=1536893890966, cause: Server side(192.168.31.31,3333) threadpool is exhausted ,detail msg:Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-192.168.31.31:3333, Pool Size: 200 (active: 200, core: 200, max: 200, largest: 200), Task: 4395 (completed: 4195), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://192.168.31.31:3333!
	at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:
<think>我们收到的问题是解决Druid连接池报错:testWhileIdle为true但未设置validationQuery的问题。根据引用内容,这个问题通常是因为当testWhileIdle设置为true时,必须设置validationQuery(一个用于检查连接有效性的SQL语句)。解决方案有两个方向:一是将testWhileIdle设置为false;二是设置一个非空的validationQuery。 根据引用[2]中的建议,我们可以这样配置(以Spring Boot的YAML配置为例): 方案1:关闭testWhileIdle(不推荐,因为testWhileIdle=true可以保证连接有效性) 方案2:设置validationQuery(推荐),同时可以调整其他相关参数。 具体配置步骤: 1. 在配置文件中,确保为Druid数据源设置validationQuery。例如,对于Oracle数据库,可以是`select 1`;对于MySQL,可以是`select 1()`或者`select 1 from dual`等。 2. 根据引用[2],还可以配置testOnBorrow和testOnReturn,但为了性能,一般将testOnBorrow和testOnReturn设为false,而将testWhileIdle设为true,并设置validationQuery。 配置示例(application.yml): ```yaml spring: datasource: druid: # 连接池配置 test-on-borrow: false # 申请连接时不检测 test-on-return: false # 归还连接时不检测 test-while-idle: true # 建议开启,在空闲时检测 validation-query: select 1 # 设置验证查询,根据数据库类型调整 # 其他配置... ``` 如果使用XML配置,如引用[3]所示,则需要设置相应的属性: ```xml <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <!-- ...其他配置... --> <property name="validationQuery" value="select 1" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> </bean> ``` 注意:validationQuery的值必须是一个能够快速执行的SQL查询语句,通常是一个简单的查询,如`select 1`。 此外,引用[1]也提到,当testWhileIdle为true时,必须设置validationQuery,否则会报错。因此,我们只需按照上述配置即可解决问题。 总结步骤: 1. 在Druid配置中,确保当testWhileIdle为true时,设置一个非空的validationQuery。 2. 根据实际数据库类型,设置合适的validationQuery(如MySQL用`select 1()`,Oracle用`select 1 from dual`,PostgreSQL用`select 1`等)。 3. 调整其他检测参数(testOnBorrow和testOnReturn)为false,以避免性能开销(但按需配置)。 相关问题: 1. 如何选择最适合的连接池健康检查策略? 2. Druid连接池中testWhileIdle、testOnBorrow和testOnReturn分别代表什么含义? 3. 不同数据库的validationQuery应该如何设置? 4. 如何监控Druid连接池的运行状态? 5. 连接池配置不当可能会引起哪些性能问题? 引用:[^1][^2][^3] </think>### 解决 Druid 连接池 `testWhileIdle=true` 但 `validationQuery` 未设置的问题 #### 问题本质分析 1. **参数依赖关系** 当 `testWhileIdle=true` 时,Druid 要求必须配置 `validationQuery` 属性: $$ \begin{cases} \text{testWhileIdle=true} \\ \downarrow \\ \text{validationQuery} \neq \text{null} \end{cases} $$ 否则会触发报错:`testWhileIdle is true, validationQuery not set` 2. **参数作用** - `testWhileIdle`:空闲连接检测开关(默认 `true`) - `validationQuery`:连接有效性验证 SQL(如 `select 1`) --- #### 完整解决方案 ##### 方案 1:关闭空闲检测(不推荐) ```yaml spring: datasource: druid: test-while-idle: false # 关闭检测 ``` > ⚠️ 缺点:可能导致使用失效数据库连接 ##### 方案 2:设置验证 SQL(推荐) ```yaml spring: datasource: druid: test-while-idle: true # 保持开启 validation-query: "select 1" # 关键配置 # 可选优化参数 test-on-borrow: false # 避免每次借连接都检测 test-on-return: false # 避免每次还连接都检测 ``` **数据库适配示例**: | 数据库 | validation-query 值 | |-------------|-----------------------------| | MySQL | `select 1` | | Oracle | `select 1 from dual` | | PostgreSQL | `select 1` | | SQL Server | `select 1` | ##### 方案 3:XML 配置方式(传统项目) ```xml <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="testWhileIdle" value="true"/> <property name="validationQuery" value="select 1"/> <!-- 必须添加 --> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> </bean> ``` --- #### 参数原理详解 | 参数 | 默认值 | 作用 | 性能影响 | |--------------------|--------|----------------------------------------------------------------------|----------| | `test-while-idle` | true | 定期检测空闲连接有效性 | 低 | | `validation-query` | null | 验证SQL语句 | - | | `test-on-borrow` | false | **每次**获取连接时检测 | 高 | | `test-on-return` | false | **每次**归还连接时检测 | 高 | > 📌 **最佳实践**:开启 `test-while-idle` + 设置 `validation-query` + 关闭 `test-on-borrow`/`test-on-return`[^1][^2] --- #### 排查流程图 ```mermaid graph TD A[报错 testWhileIdle=true validationQuery not set] --> B{检查配置文件} B -->|YAML/Properties| C[确认 druid.validation-query 是否设置] B -->|XML| D[确认 <property name="validationQuery" 是否存在] C -->|未设置| E[添加 validation-query: select 1] D -->|未设置| F[添加 <property name="validationQuery" value="select 1"/>] E --> G[重启应用验证] F --> G ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值