apache連接池的連接有效性
server一般會配置keep-alive超時時間,過了這個時間還沒新請求到來,則關閉連接。客戶端從連接池里拿出連接時,會檢查一下連接是否已關閉,如已關閉,會丟棄掉該連接,并嘗試從連接池再拿一個新的連接,代碼機制在AbstractConnPool.lease方法里:
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方法:
//CPool.java
protected boolean validate(CPoolEntry entry) {return !((ManagedHttpClientConnection)entry.getConnection()).isStale();}
那么一個連接是如何判定不新鮮(stale)的呢?邏輯如下:
//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的超時時間,像這樣:
app = FastAPI()@app.get("/test")
async def root():return "Hello fastapi"if __name__ == "__main__":import uvicornuvicorn.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個請求后關閉連接:
<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 connectionmaxKeepAliveRequests:
Maximum number of Keep-Alive requests to honor per connection