当前位置:   article > 正文

Mysql-Druid连接池配置_druid useunfairlock

druid useunfairlock

1. 背景

DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池。

2. 介绍

(1)DataSource中URL重要配置参数(Spring配置前缀:spring.datasource.url)

配置缺省值说明推荐说明
serverTimezone 时区Asia/Shanghai
useUnicode  true
characterEncoding 

1、存数据

数据库在存放项目数据的时候会先用UTF-8格式将数据解码成字节码,然后再将解码后的字节码重新使用GBK编码,并存放到数据库中。

2、取数据

在数据库中取数据的时候,数据库会先将数据库中的数据按GBK格式解码成字节码,然后再将解码后的字节码重新按UTF-8格式编码数据,最后再将数据返回给客户端

UTF8
useSSLtrueMySQL在高版本需要指明是否进行SSL连接false

(2)Druid重要配置参数(Spring配置前缀:spring.datasource.druid)

配置缺省值描述推荐说明
initial-size0初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时连接数=(核心数 * 2) + 有效磁盘数)
min-idle 最小连接池数量与initialSize一致
max-idle8最大连接池数量 
max-wait 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁 
use-unfair-lockfalse如果设置了maxWait,则启用公平锁 
time-between-eviction-runs-millis60000在空闲连接回收器线程运行期间休眠时间,它决定线程多久验证空闲连接或丢弃连接的频率源码上看,是通过validation-query配置的语句语句检测连接的有效性,如果连接失败了则丢弃
min-evictableIdle-time-millis1800000连接在池中保持空闲而不被回收的最小时间 
validation-query 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用false如果检测到已知驱动后,会使用MySqlValidConnectionChecker类进行有效检测,走的是ping策略,而不是该配置,哪怕没有配置也会走默认的 “select 1”,前提是使用MySqlValidConnectionChecker,不然是直接返回true的
validation-query-timeout-1检测连接超时时间虽然这里默认是-1,但是实际代码会设置成1s的时间
test-on-borrowfalse申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 
test-while-idletrue建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效 
test-on-returnfalse归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 
pool-prepared-statementsfalse是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭 
max-open-prepared-statements-1要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 
filter-class-names   
flter.stat.slow-sql-millis   

3. 源码

 

4. 实战

4.1 数据库连接配置

  1. spring:
  2. datasource:
  3. url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF8&useSSL=false
  4. username: root
  5. password: root
  6. driver-class-name: com.mysql.cj.jdbc.Driver

4.2 Druid配置

以数据库实例是4核8G为例(待考量):

  1. spring:
  2. datasource:
  3. druid:
  4. initial-size: 10
  5. min-idle: 10
  6. max-active: 25
  7. max-wait: 60000
  8. use-unfair-lock: true
  9. time-between-eviction-runs-millis: 60000
  10. min-evictable-idle-time-millis: 300000

5. FAQ

5.1 Druid是否有必要在设置了maxWait后,还要强制设置useUnfairLock=true?

设置后,性能会翻倍(见参考资料有赞优化),但是这样做有没有其他问题?

5.2  检测到连接达空闲时间上线时,Druid会物理关闭该连接,那么它不保证最小连接数吗?会重新开启新的连接吗?

(1) com.alibaba.druid.pool.DruidDataSource#getConnectionDirect

  1. public DruidPooledConnection getConnectionDirect(long maxWaitMillis) throws SQLException {
  2. int notFullTimeoutRetryCnt = 0;
  3. for (;;) {
  4. // ...
  5. if (testOnBorrow) {
  6. // ...
  7. } else {
  8. if (poolableConnection.conn.isClosed()) {
  9. discardConnection(poolableConnection.holder); // 传入null,避免重复关闭
  10. continue;
  11. }
  12. if (testWhileIdle) {
  13. final DruidConnectionHolder holder = poolableConnection.holder;
  14. long currentTimeMillis = System.currentTimeMillis();
  15. long lastActiveTimeMillis = holder.lastActiveTimeMillis;
  16. long lastExecTimeMillis = holder.lastExecTimeMillis;
  17. long lastKeepTimeMillis = holder.lastKeepTimeMillis;
  18. if (checkExecuteTime
  19. && lastExecTimeMillis != lastActiveTimeMillis) {
  20. lastActiveTimeMillis = lastExecTimeMillis;
  21. }
  22. if (lastKeepTimeMillis > lastActiveTimeMillis) {
  23. lastActiveTimeMillis = lastKeepTimeMillis;
  24. }
  25. long idleMillis = currentTimeMillis - lastActiveTimeMillis;
  26. long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
  27. if (timeBetweenEvictionRunsMillis <= 0) {
  28. timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
  29. }
  30. // 如果空闲时间达到阙值
  31. if (idleMillis >= timeBetweenEvictionRunsMillis
  32. || idleMillis < 0 // unexcepted branch
  33. ) {
  34. // 检测连接是否有效
  35. boolean validate = testConnectionInternal(poolableConnection.holder, poolableConnection.conn);
  36. if (!validate) {
  37. if (LOG.isDebugEnabled()) {
  38. LOG.debug("skip not validate connection.");
  39. }
  40. // 无效则关闭连接
  41. discardConnection(poolableConnection.holder);
  42. continue;
  43. }
  44. }
  45. }
  46. }
  47. // ...
  48. }

(2) 关闭连接后,如果当前存活数小于最小连接数

空信号的处理利用的是AQS的Condition.sign(),这里还不确定会不会开启。Condition忘记了~

  1. public void discardConnection(DruidConnectionHolder holder) {
  2. if (holder == null) {
  3. return;
  4. }
  5. Connection conn = holder.getConnection();
  6. if (conn != null) {
  7. JdbcUtils.close(conn);
  8. }
  9. lock.lock();
  10. try {
  11. if (holder.discard) {
  12. return;
  13. }
  14. if (holder.active) {
  15. activeCount--;
  16. holder.active = false;
  17. }
  18. discardCount++;
  19. holder.discard = true;
  20. if (activeCount <= minIdle) {
  21. emptySignal();
  22. }
  23. } finally {
  24. lock.unlock();
  25. }
  26. }

 

6. 参考资料

有赞DB连接池性能优化

数据库连接池的大小配置

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/46389?site
推荐阅读
相关标签
  

闽ICP备14008679号