在HTTP/1.0中keep-alive不是標準協議,客戶端必須發送Connection:Keep-Alive來激活keep-alive鏈接。
HTTP協議是無狀態的協議,即每一次請求都是互相獨立的。所以它的最初實現是,每個http請求都會打開一個tcp socket鏈接,當交互完畢後會關閉這個鏈接。
HTTP協議是全雙工的協議,因此創建鏈接與斷開鏈接是要通過三次握手與四次揮手的。顯然在這種設計中,每次發送Http請求都會消耗不少的額外資源,即鏈接的創建與銷燬。
因而,HTTP協議的也進行了發展,經過持久鏈接的方法來進行socket鏈接複用。
從圖中能夠看到:
- 在串行鏈接中,每次交互都要打開關閉鏈接
- 在持久鏈接中,第一次交互會打開鏈接,交互結束後鏈接並不關閉,下次交互就省去了創建鏈接的過程。
持久鏈接的實現有兩種:HTTP/1.0+的keep-alive與HTTP/1.1的持久鏈接。
HTTP/1.1的鏈接默認狀況下都是持久鏈接。若是要顯式關閉,須要在報文中加上Connection:Close首部。不發送Connection:Close不意味着服務器承諾鏈接永遠保持打開。即在HTTP/1.1中,全部的鏈接都進行了複用。
HttpClien中使用了鏈接池來管理持有鏈接,同一條TCP鏈路上,鏈接是能夠複用的。HttpClient經過鏈接池的方式進行鏈接持久化。
其實「池」技術是一種通用的設計,其設計思想並不複雜:
- 當有鏈接第一次使用的時候創建鏈接
- 結束時對應鏈接不關閉,歸還到池中
- 下次同個目的的鏈接可從池中獲取一個可用鏈接
- 按期清理過時鏈接 以下:
在HttpClient4.4版本以前,在從鏈接池中獲取重用鏈接的時候會檢查下是否過時,過時則清理。
以後的版本則不一樣,會有一個單獨的線程來掃描鏈接池中的鏈接,發現有離最近一次使用超過設置的時間後,就會清理。默認的超時時間是2秒鐘。
總結
- HTTP協議經過持久鏈接的方式,減輕了早期設計中的過多鏈接問題
- 持久鏈接有兩種方式:HTTP/1.0+的Keep-Avlive與HTTP/1.1的默認持久鏈接
- HttpClient經過鏈接池來管理持久鏈接,鏈接池分爲兩個,一個是總鏈接池,一個是每一個route對應的鏈接池
- 默認鏈接重用策略與HTTP協議約束一致,根據response先判斷Connection:Close則關閉,在判斷Connection:Keep-Alive則開啓,最後版本大於1.0則開啓
- 只有在HttpClientBuilder中手動開啓了清理過時與空閒鏈接的開關後,纔會清理鏈接池中的鏈接
- HttpClient4.4以後的版本經過一個死循環線程清理過時與空閒鏈接,該線程每次執行都sleep一會,以達到按期執行的效果