奥利给!阿里的Druid来告诉你池化技术有多牛

本文详细探讨了阿里Druid连接池的工作原理,包括初始化、连接获取、连接检查、连接回收等关键流程。通过分析连接池生命周期,揭示了Druid如何保证性能和连接可用性,以及在不同场景下的配置建议。同时,文章提醒了配置testOnBorrow和testOnReturn对性能的影响,并讨论了避免长时间等待连接的策略。
摘要由CSDN通过智能技术生成

##零、类图&流程预览

本文会通过getConnection作为入口,探索在druid里,一个连接的生命周期。大体流程被划分成了以下几个主流程:

##主流程1:获取连接流程

首先会调用init进行连接池的初始化,然后运行责任链上的每一个filter,最终执行getConnectionDirect获取真正的连接对象,如果开启了testOnBorrow,则每次都会去测试连接是否可用(这也是官方不建议设置testOnBorrow为true的原因,影响性能,这里的测试是指测试mysql服务端的长连接是否断开,一般mysql服务端长连保活时间是8h,被使用一次则刷新一次使用时间,若一个连接距离上次被使用超过了保活时间,那么再次使用时将无法与mysql服务端通信)。

如果testOnBorrow没有被置为true,则会进行testWhileIdle的检查(这一项官方建议设置为true,缺省值也是true),检查时会判断当前连接对象距离上次被使用的时间是否超过规定检查的时间,若超过,则进行检查一次,这个检查时间通过timeBetweenEvictionRunsMillis来控制,默认60s

每个连接对象会记录下上次被使用的时间,用当前时间减去上一次的使用时间得出闲置时间,闲置时间再跟timeBetweenEvictionRunsMillis比较,超过这个时间就做一次连接可用性检查,这个相比testOnBorrow每次都检查来说,性能会提升很多,用的时候无需关注该值,因为缺省值是true,经测试如果将该值设置为falsetestOnBorrow也设置为false,数据库服务端长连保活时间改为60s60s内不使用连接,超过60s后使用将会报连接错误。


若使用testConnectionInternal方法测试长连接结果为false,则证明该连接已被服务端断开或者有其他的网络原因导致该连接不可用,则会触发discardConnection进行连接回收(对应流程1.4,因为丢弃了一个连接,因此该方法会唤醒主流程3进行检查是否需要新建连接)。整个流程运行在一个死循环内,直到取到可用连接或者超过重试上限报错退出(在连接没有超过连接池上限的话,最多重试一次(重试次数默认重试1次,可以通过notFullTimeoutRetryCount属性来控制),所以取连接这里一旦发生等待,在连接池没有满的情况下,最大等待2 × maxWait 的时间 ←这个有待验证)。

##特别说明①

为了保证性能,不建议将testOnBorrow设置为true,或者说牵扯到长连接可用检测的那几项配置使用druid默认的配置就可以保证性能是最好的,如上所说,默认长连接检查是60s一次,所以不启用testOnBorrow的情况下要想保证万无一失,自己要确认下所连的那个mysql服务端的长连接保活时间(虽然默认是8h,但是dba可能给测试环境设置的时间远小于这个时间,所以如果这个时间小于60s,就需要手动设置timeBetweenEvictionRunsMillis了,如果mysql服务端长连接时间是8h或者更长,则用默认值即可。

##特别说明②

为了防止不必要的扩容,在mysql服务端长连接够用的情况下,对于一些qps较高的服务、网关业务,建议把池子的最小闲置连接数minIdle和最大连接数maxActive设置成一样的,且按照需要调大,且开启keepAlive进行连接活性检查(参考流程4.1),这样就不会后期发生动态新建连接的情况(建连还是个比较重的操作,所以不如一开始就申请好所有需要的连接,个人意见,仅供参考),但是像管理后台这种,长期qps非常低,但是有的时候需要用管理后台做一些巨大的操作(比如导数据什么的)导致需要的连接暴增,且管理后台不会特别要求性能,就适合将minIdle的值设置的比maxActive小,这样不会造成不必要的连接浪费,也不会在需要暴增连接的时候无法动态扩增连接。


##主流程2:初始化连接池

通过上面的流程图可以看到,在获取一个连接的时候首先会检查连接池是否已经初始化完毕(通过inited来控制,bool类型,未初始化为flase,初始化完毕为true,这个判断过程在init方法内完成),若没有初始化,则调用init进行初始化(图主流程1中的紫色部分),下面来看看init方法里又做了哪些操作:

可以看到,实例化的时候会初始化全局的重入锁lock,在初始化过程中包括后续的连接池操作都会利用该锁保证线程安全,初始化连接池的时候首先会进行双重检查是否已经初始化过,若没有,则进行连接池的初始化,这时候还会通过SPI机制额外加载责任链上的filter。

但是这类filter需要在类上加上@AutoLoad注解。然

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值