入门参考:
官方文档:
github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE
参考其中配置。
ConnectionPool
|---------------------------|
| |
getConnection | |
(notEmpty.await) | |
(lowWater.signal) | |
(maxActive.await) | |
<-------------------------- | |
<-------------------------- | |
<-------------------------- | |
| |
| |
--------------------------> | |
--------------------------> | | 销毁多余连接的线程
--------------------------> | | (highWater.awati, idleTimeout.await)
close | | -------------------------------------->
(highWater.signal) | |
(maxActive.signal) | |
| |
| |
产生连接的线程 | |
(lowWater.await) | |
(notEmpty.signal) | |
--------------------------> | |
| |
|---------------------------|
五个Condition:notEmpty、maxActive、lowWater、hightWater, idleTime
public Connection createPhysicalConnection(String url, Properties info) throws SQLException {
Connection conn;
if (getProxyFilters().size() == 0) {
conn = getDriver().connect(url, info);
} else {
conn = new FilterChainImpl(this).connection_connect(info);
}
createCountUpdater.incrementAndGet(this);
return conn;
}
对比proxool连接池:
proxool太古老,不方便监控,参数控制等也有些问题:比如
maximumConnectionLifetime 是通过创建时间来控制的:
/**
* The age in millseconds since this connection was built
*/
long getAge();
以下是过期清理的代码:
HouseKeeper.sweep()
// Now to check whether the connection is due for expiry
if (proxyConnection.getAge() > definition.getMaximumConnectionLifetime()) {
final String reason = "age is " + proxyConnection.getAge() + "ms";
// Check whether we can make it offline
if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_OFFLINE)) {
if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL)) {
// It is. Expire it now .
connectionPool.expireProxyConnection(proxyConnection, ConnectionListenerIF.MAXIMUM_CONNECTION_LIFETIME_EXCEEDED, reason, ConnectionPool.REQUEST_EXPIRY);
}
} else {
// Oh no, it's in use. Never mind, we'll mark it for expiry
// next time it is available. This will happen in the
// putConnection() method.
proxyConnection.markForExpiry(reason);
if (log.isDebugEnabled()) {
log.debug(connectionPool.displayStatistics() + " - #" + FormatHelper.formatMediumNumber(proxyConnection.getId())
+ " marked for expiry.");
}
} // END if (poolableConnection.setOffline())
} // END if (poolableConnection.getAge() > maximumConnectionLifetime)
生产连接池,小于minimumConnectionCount则添加,小于最小空闲数prototypeCount也添加。
Prototyper.sweep()
while (!cancel && connectionPool.isConnectionPoolUp()) {
String reason = null;
if (connectionCount >= getDefinition().getMaximumConnectionCount()) {
// We don't want to make any more that the maximum
break;
} else if (connectionCount < getDefinition().getMinimumConnectionCount()) {
reason = "to achieve minimum of " + getDefinition().getMinimumConnectionCount();
} else if (connectionPool.getAvailableConnectionCount() < getDefinition().getPrototypeCount()) {
reason = "to keep " + getDefinition().getPrototypeCount() + " available";
} else {
// Nothing to do
break;
}
ProxyConnectionIF freshlyBuiltProxyConnection = null;
try {
// If it has been shutdown then we should just stop now.
if (!connectionPool.isConnectionPoolUp()) {
break;
}
freshlyBuiltProxyConnection = buildConnection(ConnectionInfoIF.STATUS_AVAILABLE, reason);
somethingDone = true;
} catch (Throwable e) {
log.error("Prototype", e);
}
}
以上就会造成非高峰期时间段内,如果最小值配的比较大,会固定回收时间重新创建一次连接池的最小个数。
而druid没有这个问题:
DruidDataSource.shrink()
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];
if (checkTime) {
if (phyTimeoutMillis > 0) {
long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
if (phyConnectTimeMillis > phyTimeoutMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}
long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;
if (idleMillis < minEvictableIdleTimeMillis) {
break;
}
if (checkTime && i < checkCount) {
evictConnections[evictCount++] = connection;
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
} else if (keepAlive) {
keepAliveConnections[keepAliveCount++] = connection;
}
} else {
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
}