2.6 连接池管理
在dble中每个后端MySQL节点由 PhysicalDbInstance 表示,PhysicalDbInstance中维护了两类连接:
- 大部分业务使用的连接由连接池管理
- 独立于连接池之外的连接,这类连接主要有两类:MySQL实例的心跳连接和用于OneTimeJob的一次性任务的连接,这种连接是一次性的,用完即关,次数也比较少。
2.6.1 dble后端连接池管理
后端连接池使用 CopyOnWriteArrayList 存储该MySQL实例的全量连接,通过连接的state状态来维护连接的初始化,借出,空闲,心跳,移除状态。连接池初始化之后会维护一个evictor线程来维持连接池的扩缩容以及空闲连接的有效性。结构如下图所示:
2.6.1.1 连接获取
业务向连接池请求获取后端连接,会遍历连接池中的全量连接直到找到第一个空闲连接。若连接池中当时没有空闲连接,则线程会进入超时等待队列,在超时时间内未获取到连接,前端报错。
2.6.1.2 连接释放
后端连接处理完业务之后,状态会被置为空闲,并且处理线程会唤醒在超时等待队列中的线程来重新获取连接。
2.6.1.3 连接池扩缩容
连接池初始化之后会维护一个evictor线程来维持连接池的扩缩容以及空闲连接的有效性,evictor线程是一个定时任务。
扩容:当空闲连接数小于minCon时,维持连接池中的空闲连接在minCon的数量上,每次扩容的连接数量通过以下公式计算:min(配置的最小空闲连接数 - 当前连接池中空闲连接数, 配置的最大连接数 - 连接池中的总连接数) - 正在创建的连接数,若数量大于0,则创建该数量的连接。
缩容:当空闲连接数大于minCon时,维持连接池中的空闲连接在minCon的数量上,每次关闭的连接数量通过以下公式计算:(连接池中的最小连接数 - 配置的最小连接) > 0 && 连接达到 idleTimeout。
2.6.1.4 连接有效性检测
在连接的不同阶段,提供对连接有效性的检测手段。
- testOnCreate为true,在连接被创建后,会发送ping命令探测连接有效性,若在connectionHeartbeatTimeout没有收到结果,会关闭连接。
- testOnBorrow为true,在连接被借出后,会发送ping命令探测连接有效性,若在connectionHeartbeatTimeout没有收到结果,会关闭连接。
- testOnReturn为true,在连接被返回后,会发送ping命令探测连接有效性,若在connectionHeartbeatTimeout没有收到结果,会关闭连接。
- testWhileIdle为true,对所有空闲连接,发送ping命令探测连接有效性,若在connectionHeartbeatTimeout没有收到结果,会关闭连接。
2.6.2 连接状态管理
由上文我们知道,后端连接池使用 CopyOnWriteArrayList 存储该MySQL实例的全量连接,通过连接的state状态来维护连接的初始化,借出,空闲,心跳,移除状态。下面是连接状态的跃迁图:
2.6.3 连接流量控制阈值
dble对分库分表的流量有控制功能,详见2.25 dble流量控制。
后端连接的高水位(flowHighLevel)和低水位(flowLowLevel)的配置也在这里体现,单位字节
2.6.4 连接池属性
属性名 | 默认值 | 单位 | 含义 |
---|---|---|---|
testOnCreate | false | 无 | 连接创建后是否检测有效性 |
testOnBorrow | false | 无 | 连接被借出后是否检测有效性 |
testOnReturn | false | 无 | 连接被返回时是否检测有效性 |
testWhileIdle | false | 无 | 连接空闲时是否检测有效性 |
connectionTimeout | 30000 (30s) | 毫秒 | 获取连接的超时时间 |
connectionHeartbeatTimeout | 20 | 毫秒 | 空闲连接检测后的超时时间 |
timeBetweenEvictionRunsMillis | 30000 (30s) | 毫秒 | 扩缩容线程的检测周期 |
idleTimeout | 600000 (10 minute) | 毫秒 | 连接空闲多久之后被回收 |
heartbeatPeriodMillis | 10000 (10s) | 毫秒 | 连接池的心跳周期 |
evictorShutdownTimeoutMillis | 10000 (10s) | 毫秒 | 扩缩容线程停止的超时时间 |
flowHighLevel | 4194304 | 字节 | 后端连接流量控制的高水位 |
flowLowLevel | 262144 | 字节 | 后端连接流量控制的低水位 |
示例:
<?xml version="1.0"?>
<!DOCTYPE dble:db SYSTEM "db.dtd">
<dble:db xmlns:dble="http://dble.cloud/">
<dbGroup name="dbGroup1" rwSplitMode="1" delayThreshold="10000">
<heartbeat errorRetryCount="1" timeout="10" keepAlive="60" >show slave status</heartbeat>
<dbInstance name="instanceM1" url="ip4:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="true">
<property name="testOnCreate">false</property>
<property name="testOnBorrow">false</property>
<property name="testOnReturn">false</property>
<property name="testWhileIdle">true</property>
<property name="connectionTimeout">30000</property>
<property name="connectionHeartbeatTimeout">20</property>
<property name="timeBetweenEvictionRunsMillis">30000</property>
<property name="idleTimeout">600000</property>
<property name="heartbeatPeriodMillis">10000</property>
<property name="evictorShutdownTimeoutMillis">10000</property>
<property name="flowHighLevel">4194304 </property>
<property name="flowLowLevel">262144 </property>
</dbInstance>
<!-- can have multi read instances -->
<dbInstance name="instanceS1" url="ip5:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="false">
<property name="heartbeatPeriodMillis">60000</property>
</dbInstance>
</dbGroup>
</dble:db>
2.6.5 dble后端连接池的心跳管理
dble后端MySQL节点的心跳管理是通过定时任务来完成的,检测周期由heartbeatPeriodMillis来控制。dble会对每一个后端MySQL节点持有一个长连接,定期发送心跳语句,根据返回结果的不同将连接池标记为不同的状态。若心跳异常,会影响evictor线程的扩缩容。
2.6.5.1 心跳周期内的不同阶段
我们可以将每个心跳周期简单划分为两个阶段:
- 检测阶段:心跳检测发起到收到回复的阶段
- 空闲阶段:心跳返回后到下一个心跳检测发起的阶段
2.6.5.2 心跳状态
dble的心跳状态有四种:
- init状态:初始状态,具体指收到第一个心跳响应报文前的状态
- ok状态:收到一次正常的心跳返回后的状态
- timeout状态:最近的一次心跳在HeartbeatTimeout时间段内没有收到响应
- error状态:心跳语句返回错误或者心跳连接异常都可能导致此种状态,dble里面会有重试机制来预防网络抖动等网络方面的异常。
2.6.5.3 心跳重试
此处的心跳重试分为三种情况:第一种是心跳语句返回错误导致的重试,第二种是心跳连接关闭导致的重试,第三种是心跳超时后才收到响应导致的重试。
- 对于心跳语句返回失败,dble会立即将连接池状态置为error状态,随即会发送errorRetryCount次心跳,若有一次心跳正常,心跳恢复成ok状态。
- 对于心跳连接关闭引起的失败,dble会在接下来的时间立即发送errorRetryCount次心跳,若有一次心跳正常,则停止重试,但如果都失败,则将连接池状态置为error状态
- 对于标记为timeout状态后收到姗姗来迟的OK响应, 则将会被重置为init状态并立即发送一次心跳。
2.6.6 连接池补充说明
在dble中,dble会与配置的数据库建立连接,db.xml中的dbInstance标签中配置了具体的数据库实例,dble与数据库的连接通过连接池来管理。
- 每个dbInstance的连接池都是独立的,连接池的连接数通过dbInstance中的maxCon参数和minCon参数来控制
- 每一个dbInstance中配置的mysql实例,dble都会建立一个连接池来管理。只有在rwSplitMode=0时,主实例会建立连接池,从实例不会建立连接池
举例:
<dbGroup name="dbGroup1" rwSplitMode="1" delayThreshold="10000">
<heartbeat errorRetryCount="1" timeout="10" keepAlive="60">show slave status</heartbeat>
<dbInstance name="instanceM1" url="ip4:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="true">
</dbInstance>
</dbGroup>
<dbGroup name="dbGroup2" rwSplitMode="1" delayThreshold="10000">
<heartbeat errorRetryCount="1" timeout="10" keepAlive="60">show slave status</heartbeat>
<dbInstance name="instanceM2" url="ip4:3306" user="your_user" password="your_psw" maxCon="100" minCon="10" primary="true">
</dbInstance>
</dbGroup>
<dbGroup name="dbGroup3" rwSplitMode="1" delayThreshold="10000">
<heartbeat errorRetryCount="1" timeout="10" keepAlive="60">show slave status</heartbeat>
<dbInstance name="instanceM3" url="ip5:3306" user="your_user" password="your_psw" maxCon="200" minCon="50" primary="true">
</dbInstance>
</dbGroup>
配置注意事项:
1.instanceM1和instanceM2虽然配置了相同mysql,dble是根据dbInstance来建立连接池,上述例子中总共会建立三个连接池
2.instanceM1和instanceM2虽然配置了相同mysql,连接池中都是相互独立的,instanceM1的连接池中连接数量最大为200,最小为50,instanceM2的连接池中连接数量最大为100,
最小为10。二者相互独立