1、什么是keepAlive
先简单说一下keepAlive在服务架构上的工作模式
1、高可用的解决方案通常为:冗余+故障自动发现转移,当一台节点负责接收请求时,发生故障那么整个应用就停止了,这时候会启动多台服务器有一台作为master提供服务,其余的为backup,master会定期向backup发送心跳,证明master还活着。
2、那么每台服务器的ip肯定是不同的,这时候会有一个虚拟ip在master上,client发起的请求都是请求的这个虚拟ip,master宕机后,重新发起ARP广播,刷新mac地址,并且把虚拟ip给新选举成功的服务器上,这样就做到了高可用。
keepAlive保活机制目的就来保障整个集群的高可用性
那么,keepAlive思想在Druid连接池中是如何运用的?
2、keepAlive在Druid连接池中的作用
存活机制能够保证连接池中的连接是真实有效的连接,假如遇到特殊情况导致连接不可用时,keepAlive机制将无效连接进行驱逐。
开启keepAlive
// 一个连接在连接池中最小生存的时间
dataSurce.setMinEvictableIdleTimeMillis(60 * 1000);单位毫秒
// 开启keepAlive
dataSource.setKeepAlive(true);
当连接池中连接的空闲时间大于最小驱逐空闲时间,并且开启了keepAlive,那么就将该连接放入保活连接数组,并且对保活连接数组中的连接进行有效性检查。
先看DruidDataSource中的两个成员变量
// 存放检查需要抛弃的连接
private DruidConnectionHolder[] evictConnections;
// 用来存放需要连接检查的存活连接
private DruidConnectionHolder[] keepAliveConnections;
createAndStartdestroyThread()创建的destroytask线程
destroy守护线程无限循环destroyTask线程
@Override
public void run() {
shrink(true, keepAlive);
if (isRemoveAbandoned()) {
removeAbandoned();
}
}
关键方法shrink(true,keepAlive)
public void shrink(boolean checkTime, boolean keepAlive) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}
// 是否需要填充,开启keepAlive并且池中可用连接数+正在使用连接 < minIdle时,needFile=true
boolean needFill = false;
// 驱逐连接数量
int evictCount = 0;
// 存活连接数量
int keepAliveCount = 0;
int fatalErrorIncrement = fatalErrorCount - fatalErrorCountLastShrink;
fatalErrorCountLastShrink = fatalErrorCount;
try {
// 未init直接return
if (!inited) {
return;
}
// 池中可用连接数 - 最小连接数 = 待检查的连接数量
// 检测连接存活有效性,也是从这批连接中进行检查
final int checkCount = poolin