在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一会,以达到定期执行的效果