江苏中兴建设有限公司网站,wordpress 简易教程,设计师常去的网站,包装设计公司 山东短连接
HTTP 协议最初#xff08;0.9/1.0#xff09;是个非常简单的协议#xff0c;通信过程也采用了简单的“请求 - 应答”方式。 它底层的数据传输基于 TCP/IP#xff0c;每次发送请求前需要先与服务器建立连接#xff0c;收到响应报文后会立即关闭连接。 因为客户端与…短连接
HTTP 协议最初0.9/1.0是个非常简单的协议通信过程也采用了简单的“请求 - 应答”方式。 它底层的数据传输基于 TCP/IP每次发送请求前需要先与服务器建立连接收到响应报文后会立即关闭连接。 因为客户端与服务器的整个连接过程很短暂不会与服务器保持长时间的连接状态所以就被称为“短连接”short-lived connections。早期的 HTTP 协议也被称为是“无连接”的协议。
举例子
假设你的公司买了一台打卡机放在前台因为这台机器比较贵所以专门做了一个保护罩盖着它公司要求每次上下班打卡时都要先打开盖子打卡后再盖上盖子。 可是偏偏这个盖子非常牢固打开关闭要费很大力气打卡可能只要 1 秒钟而开关盖子却需要四五秒钟大部分时间都浪费在了毫无意义的开关盖子操作上了。 可想而知平常还好说一到上下班的点在打卡机前就会排起长队每个人都要重复“开盖 -打卡 - 关盖”的三个步骤你说着急不着急。 在这个比喻里打卡机就相当于服务器盖子的开关就是 TCP 的连接与关闭而每个打卡的人就是 HTTP 请求很显然短连接的缺点严重制约了服务器的服务能力导致它无法处理更多的请求。
长连接
针对短连接暴露出的缺点HTTP 协议就提出了“长连接”的通信方式也叫“持久连接”persistent connections、“连接保活”keep alive、“连接复用”connection reuse。 其实解决办法也很简单用的就是“成本均摊”的思路既然 TCP 的连接和关闭非常耗时间那么就把这个时间成本由原来的一个“请求 - 应答”均摊到多个“请求 - 应答”上。 这样虽然不能改善 TCP 的连接效率但基于“分母效应”每个“请求 - 应答”的无效时间就会降低不少整体传输效率也就提高了。
短连接与长连接的对比示意图 继续用刚才的打卡机的比喻公司也觉得这种反复“开盖 - 打卡 - 关盖”的操作太“反人类”了于是颁布了新规定早上打开盖子后就不用关上了可以自由打卡到下班后再关上盖子。 这样打卡的效率即服务能力就大幅度提升了原来一次打卡需要五六秒钟现在只要一秒就可以了上下班时排长队的景象一去不返大家都开心。
连接相关的头字段
由于长连接对性能的改善效果非常显著所以在 HTTP/1.1 中的连接都会默认启用长连接。不需要用什么特殊的头字段指定只要向服务器发送了第一次请求后续的请求都会重复利用第一次打开的 TCP 连接也就是长连接在这个连接上收发数据。 当然我们也可以在请求头里明确地要求使用长连接机制使用的字段是 Connection值是“keep-alive”。 不过不管客户端是否显式要求长连接如果服务器支持长连接它总会在响应报文里放一个“Connection: keep-alive”字段告诉客户端“我是支持长连接的接下来就用这个TCP 一直收发数据吧”。 不过长连接也有一些小缺点问题就出在它的“长”字上。 因为 TCP 连接长时间不关闭服务器必须在内存里保存它的状态这就占用了服务器的资源。如果有大量的空闲长连接只连不发就会很快耗尽服务器的资源导致服务器无法为真正有需要的用户提供服务。 所以长连接也需要在恰当的时间关闭不能永远保持与服务器的连接这在客户端或者服务器都可以做到。 在客户端可以在请求头里加上“Connection: close”字段告诉服务器“这次通信后就关闭连接”。服务器看到这个字段就知道客户端要主动关闭连接于是在响应报文里也加上这个字段发送之后就调用 Socket API 关闭 TCP 连接。 服务器端通常不会主动关闭连接但也可以使用一些策略。拿 Nginx 来举例它有两种方式 1.使用“keepalive_timeout”指令设置长连接的超时时间如果在一段时间内连接上没有任何数据收发就主动断开连接避免空闲连接占用系统资源。 2.使用“keepalive_requests”指令设置长连接上可发送的最大请求次数。比如设置成1000那么当 Nginx 在这个连接上处理了 1000 个请求后也会主动断开连接。
另外客户端和服务器都可以在报文里附加通用头字段“Keep-Alive: timeoutvalue”限定长连接的超时时间。但这个字段的约束力并不强通信的双方可能并不会遵守所以不太常见。
队头阻塞
看完了短连接和长连接接下来就要说到著名的“队头阻塞”Head-of-line blocking也叫“队首阻塞”了。 “队头阻塞”与短连接和长连接无关而是由 HTTP 基本的“请求 - 应答”模型所导致的。 因为 HTTP 规定报文必须是“一发一收”这就形成了一个先进先出的“串行”队列。队列里的请求没有轻重缓急的优先级只有入队的先后顺序排在最前面的请求被最优先处理。 如果队首的请求因为处理的太慢耽误了时间那么队列里后面的所有请求也不得不跟着一起等待结果就是其他的请求承担了不应有的时间成本。 还是用打卡机做个比喻。上班的时间点上大家都在排队打卡可这个时候偏偏最前面的那个人遇到了打卡机故障怎么也不能打卡成功急得满头大汗。等找人把打卡机修好后面排队的所有人全迟到了。
性能优化
因为“请求 - 应答”模型不能变所以“队头阻塞”问题在 HTTP/1.1 里无法解决只能缓解有什么办法呢 公司里可以再多买几台打卡机放在前台这样大家可以不用挤在一个队伍里分散打卡一个队伍偶尔阻塞也不要紧可以改换到其他不阻塞的队伍。 这在 HTTP 里就是“并发连接”concurrent connections也就是同时对一个域名发起多个长连接用数量来解决质量的问题。 但这种方式也存在缺陷。如果每个客户端都想自己快建立很多个连接用户数×并发数就会是个天文数字。服务器的资源根本就扛不住或者被服务器认为是恶意攻击反而会造成“拒绝服务”。 所以HTTP 协议建议客户端使用并发但不能“滥用”并发。RFC2616 里明确限制每个客户端最多并发 2 个连接。不过实践证明这个数字实在是太小了众多浏览器都“无视”标准把这个上限提高到了 6~8。后来修订的 RFC7230 也就“顺水推舟”取消了这个“2”的限制。 公司发展的太快了员工越来越多上下班打卡成了迫在眉睫的大问题。前台空间有限放不下更多的打卡机了怎么办那就多开几个打卡的地方每个楼层、办公区的入口也放上三四台打卡机把人进一步分流不要都往前台挤。 这个就是“域名分片”domain sharding技术还是用数量来解决质量的思路。 HTTP 协议和浏览器不是限制并发连接数量吗好那我就多开几个域名比如shard1.chrono.com、shard2.chrono.com而这些域名都指向同一台服务器www.chrono.com这样实际长连接的数量就又上去了真是“美滋滋”。不过实在是有点“上有政策下有对策”的味道。
小结
早期的 HTTP 协议使用短连接收到响应后就立即关闭连接效率很低HTTP/1.1 默认启用长连接在一个连接上收发多个请求响应提高了传输效率服务器会发送“Connection: keep-alive”字段表示启用了长连接报文头里如果有“Connection: close”就意味着长连接即将关闭过多的长连接会占用服务器资源所以服务器会用一些策略有选择地关闭长连接“队头阻塞”问题会导致性能下降可以用“并发连接”和“域名分片”技术缓解。
PS本文是观看极客之后的笔记。