Druid连接池

Druid是一个高性能的数据库连接池,旨在提高数据库连接性能和管理效率。本文将介绍在Spring框架下使用Druid连接池连接云原生数据仓库 AnalyticDB MySQL 版(以下简称AnalyticDB for MySQL)的配置参数与代码示例。

注意事项

  • 仅支持Druid 1.1.16以上的版本。

  • 使用Druid连接池连接AnalyticDB for MySQL时,建议配置<property name="keepAlive" value="true" />,可以复用连接和避免短连接。

  • AnalyticDB for MySQL前端接入节点使用SLB做负载均衡,客户端连接前端节点。为了将客户端请求较为均匀地发送到各个前端节点,建议连接池里有稍多一些连接,且连接保持的时间不宜太长。

  • 根据业务情况合理调整连接池配置,并确保配置生效。您可以在程序中通过DruidDataSource#getStatData()DruidDataSource#dump()方法定期获取生效的配置与连接池的信息,并在日志中查看、核对相关配置信息。

  • 执行查询前从连接池获取连接,执行完查询后要及时调用conn.close()将连接返回到连接池中。再次使用时,请从连接池中获取新连接,避免长时间使用一个连接导致Druid无法及时检查到连接失效。

  • 复杂网络情况下,当遇到网关性能达到瓶颈、网络链路长、网络抖动、重传率或丢包率高等情形,可能会导致连接中断。在确保连接池合理配置都生效的情况下,如果仍然有连接中断的情况,建议业务代码侧通过重试进行优化。

配置Druid连接池

 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
     <!--jdbc_url是AnalyticDB MySQL集群的连接地址URL,可以在控制台的集群信息页面获取连接URL。-->
     <property name="url" value="${jdbc_url}" />

     <!--jdbc_user是AnalyticDB MySQL集群中的用户账号:高权限账号或者普通账号。-->
     <property name="username" value="${jdbc_user}" />

     <!--jdbc_password是AnalyticDB MySQL集群中用户账号对应的密码。-->
     <property name="password" value="${jdbc_password}" />

     <!--配置初始化连接池大小、最小连接数、最大连接数。-->
     <property name="initialSize" value="5" />
     <property name="minIdle" value="10" /> 
     <property name="maxActive" value="20" />

     <!--配置获取连接等待超时的时间。-->
     <property name="maxWait" value="60000" />

     <!--配置一个连接在连接池中的最小生存时间、最大生存时间,超过最大生存时间会被移除,单位毫秒。-->
     <property name="minEvictableIdleTimeMillis" value="600000" />
     <property name="maxEvictableIdleTimeMillis" value="900000" />

     <!--配置间隔多久进行一次检测,检测需要关闭的空闲连接,单位毫秒。 默认是60s,太长可能会导致无法及时检测到连接中断。-->
     <property name="timeBetweenEvictionRunsMillis" value="2000" />

     <!--配置从连接池获取连接时,当连接空闲时间大于timeBetweenEvictionRunsMillis时是否检查连接有效性,true每次都检查;false不检查。-->
     <property name="testWhileIdle" value="true" />

     <!--配置从连接池获取连接时和向连接池归还连接时,是否检查连接有效性。-->
     <!--每次获取或归还连接都检测太频繁,除非特别重要或网络特别不可靠等情况,建议用testWhileIdle + timeBetweenEvictionRunsMillis代替。-->
     <property name="testOnBorrow" value="false" />
     <property name="testOnReturn" value="false" />

     <!--配置是否定期探活、探活间隔。-->
     <property name="keepAlive" value="true" />
     <property name="keepAliveBetweenTimeMillis" value="30000" />  <!--默认120s。-->

     <!--配置一个连接最大使用次数,避免长时间使用相同连接造成服务器端负载不均衡。-->
     <property name="phyMaxUseCount" value="1000" />

     <!--探活、验证链接有效性的查询,新版本默认使用mysqlPing代替-->
     <property name="validationQuery"  value="select 1" />
     
     <!--配置监控统计拦截的filters。-->
     <property name="filters" value="stat" /> 
 </bean>     

生效ValidationQuery

Druid新版本默认使用mysqlPing代替执行ValidationQuery进行探活,如果需要执行ValidationQuery可以进行如下设置:

...
druidDataSource.init();

Properties properties = new Properties();
properties.setProperty("druid.mysql.usePingMethod", "false");
druidDataSource.setConnectProperties(properties);

获取连接池信息

使用dataSource.dump()可以获取连接池和连接的基本信息。

{
    CreateTime:"2022-06-01 15:28:10",   # 连接池创建时间
    ActiveCount:0,      # 从连接池取出来在用的连接数
    PoolingCount:2,     # 在连接池中,未取出去使用的连接数
    CreateCount:2,      # 创建过的连接数,连接销毁后重新创建会增加该数量
    DestroyCount:0,     # 销毁过的连接数,连接异常或到期销毁会增加该数量
    CloseCount:4,       # 调用conn.close()将连接还到连接池的次数
    ConnectCount:4,     # 调用dataSource.getConnection()获取连接的次数
    Connections:[
        {
            ID:525571,     # 连接ID
            ConnectTime:"2022-06-01 15:28:11",        # 连接创建时间
            UseCount:0,                     # 连接被获取使用的次数,所有UseCount加起来等于上面的ConnectCount
            LastActiveTime:"2022-06-01 15:28:11"    # 连接最后被取出来使用的时间,未使用等于ConnectTime
        },
        {ID:1263877414, ConnectTime:"2022-06-01 15:28:11", UseCount:4, LastActiveTime:"2022-06-01 15:28:11"}
    ]
}

获取连接池生效配置

使用dataSource.getStatData()可以获取连接池生效的配置。

{
    Identity=85777802,
    Name=DataSource-85777802,
    DbType=mysql,
    DriverClassName=com.mysql.jdbc.Driver,
    URL=jdbc:mysql://host:port/db_name,
    UserName=haicen,
    FilterClassNames=[],
    WaitThreadCount=0,
    NotEmptyWaitCount=0,
    NotEmptyWaitMillis=0,
    PoolingCount=2,
    PoolingPeak=2,
    PoolingPeakTime=Wed Jun 01 16:08:15 CST 2022,
    ActiveCount=0,
    ActivePeak=1,
    ActivePeakTime=Wed Jun 01 16:08:15 CST 2022,
    InitialSize=1,
    MinIdle=2,
    MaxActive=3,
    QueryTimeout=0,
    TransactionQueryTimeout=0,
    LoginTimeout=0,
    ValidConnectionCheckerClassName=com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker,
    ExceptionSorterClassName=com.alibaba.druid.pool.vendor.MySqlExceptionSorter,
    TestOnBorrow=true,
    TestOnReturn=true,
    TestWhileIdle=true,
    DefaultAutoCommit=true,
    DefaultReadOnly=null,
    DefaultTransactionIsolation=null,
    LogicConnectCount=14,
    LogicCloseCount=14,
    LogicConnectErrorCount=0,
    PhysicalConnectCount=6,
    PhysicalCloseCount=4,
    PhysicalConnectErrorCount=0,
    DiscardCount=0,
    ExecuteCount=14,
    ExecuteUpdateCount=0,
    ExecuteQueryCount=14,
    ExecuteBatchCount=0,
    ErrorCount=0,
    CommitCount=0,
    RollbackCount=0,
    PSCacheAccessCount=0,
    PSCacheHitCount=0,
    PSCacheMissCount=0,
    StartTransactionCount=0,
    TransactionHistogram=[
        J@6a472554,
        ConnectionHoldTimeHistogram=[
            J@7ff2a664,
            RemoveAbandoned=true,
            ClobOpenCount=0,
            BlobOpenCount=0,
            KeepAliveCheckCount=332,
            KeepAlive=true,
            FailFast=false,
            MaxWait=6000,
            MaxWaitThreadCount=-1,
            PoolPreparedStatements=false,
            MaxPoolPreparedStatementPerConnectionSize=10,
            MinEvictableIdleTimeMillis=600000,
            MaxEvictableIdleTimeMillis=900000,
            LogDifferentThread=true,
            RecycleErrorCount=0,
            PreparedStatementOpenCount=0,
            PreparedStatementClosedCount=0,
            UseUnfairLock=false,
            InitGlobalVariants=false,
            InitVariants=false
}