apache连接池的连接有效性
server一般会配置keep-alive超时时间,过了这个时间还没新请求到来,则关闭连接。客户端从连接池里拿出连接时,会检查一下连接是否已关闭,如已关闭,会丢弃掉该连接,并尝试从连接池再拿一个新的连接,代码机制在AbstractConnPool.lease方法里:
java
public Future<E> lease(final T route, final Object state, final FutureCallback<E> callback) {
Args.notNull(route, "Route");
Asserts.check(!this.isShutDown, "Connection pool shut down");
return new Future<E>() {
...
public E get(long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
while(true) {
synchronized(this) {
PoolEntry var10000;
try {
E entry = (PoolEntry)this.entryRef.get();
if (entry != null) {
var10000 = entry;
} else {
...
// 从连接池租借一个连接
E leasedEntry = AbstractConnPool.this.getPoolEntryBlocking(route, state, timeout, timeUnit, this);
// 如果租借的连接未关闭,就用该连接返回之
if (AbstractConnPool.this.validateAfterInactivity <= 0 || leasedEntry.getUpdated() + (long)AbstractConnPool.this.validateAfterInactivity > System.currentTimeMillis() || AbstractConnPool.this.validate(leasedEntry)) {
if (!this.done.compareAndSet(false, true)) {
AbstractConnPool.this.release(leasedEntry, true);
throw new ExecutionException(AbstractConnPool.operationAborted());
}
this.entryRef.set(leasedEntry);
this.done.set(true);
AbstractConnPool.this.onLease(leasedEntry);
if (callback != null) {
callback.completed(leasedEntry);
}
var10000 = leasedEntry;
return var10000;
}
// 租借的连接已关闭,关闭该连接,并回到while循环开始,继续调用getPoolEntryBlocking获得新的连接,若池子里没有连接,创建一个新连接。
leasedEntry.close();
AbstractConnPool.this.release(leasedEntry, false);
continue;
}
} catch (IOException var8) {
...
}
return var10000;
}
}
}
};
}
AbstractConnPool.this.validate会调用connection的isStale方法:
java
//CPool.java
protected boolean validate(CPoolEntry entry) {
return !((ManagedHttpClientConnection)entry.getConnection()).isStale();
}
那么一个连接是如何判定不新鲜(stale)的呢?逻辑如下:
java
//BHttpConnectionBase.java
public boolean isStale() {
if (!this.isOpen()) {
return true;
} else {
try {
int bytesRead = this.fillInputBuffer(1);
return bytesRead < 0;
} catch (SocketTimeoutException var2) {
return false;
} catch (IOException var3) {
return true;
}
}
}
fillInputBuffer方法会尝试从socket里读取字节,返回值为读取的字节数,若返回-1,说明连接已关闭。
顺带说一下,实测发现,isStale的判定对于server端正常或异常关闭连接的情况,都能检测到。
各web服务器的keep-alive策略配置
很显然,一个用于生产的web服务器是要配置keep-alive超时的,毕竟机器的IO连接资源有限,万一大量的长连接被占用,新来的请求将得不到服务。
fastAPI可以在启动时指定keepalive的超时时间,像这样:
python
app = FastAPI()
@app.get("/test")
async def root():
return "Hello fastapi"
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8002, timeout_keep_alive=600)
这里我们指定600s,默认keepalive超时是5s,即5s没有请求则关闭连接
tomcat的keep-alive策略配置在server.xml里,除了keepAliveTimeout之外,还有maxKeepAliveRequests选项,意思是服务多少个请求后就关闭连接,例如下面的例子,在服务5个请求后关闭连接:
xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="1000"
acceptCount="100"
redirectPort="8443"
URIEncoding="UTF-8"
maxKeepAliveRequests="5"/>
两个参数的含义如下:
keepAliveTimeout:
The number of milliseconds Tomcat will wait for a subsequent request before closing the connection
maxKeepAliveRequests:
Maximum number of Keep-Alive requests to honor per connection