要强的 TCP
什么!TCP 沉不住气了,听说他对于请求优化也有一定的心得,这不一天一次圆桌会议即将开启,TCP 要搞个大动作!
圆桌会议
“又到了一月一次的总结大会,大家说说最近工作上出现的问题吧。” 浏览器老大坐在圆桌最前端,说道:“好意见赶紧提,吐槽也可以说。”
“我!我!我!” TCP
喊道。
“嗯,你说。”
“上次你们优化请求,怎么没叫上我呢?对于请求速度优化我也有点想法!” TCP
说道。
“上次啊,我其实也就是到 HTTP
那儿抱怨了一句,主要还是 HTTP
和他服务器的朋友一起弄好的。” 浏览器老大看了 HTTP
一眼,眼中满是得意,转头看向 TCP
说道:“说说你的想法吧。”
“上次你们弄缓存时,我也仔细的查看了一下通过我发送的报文,总结出来一个规律。” 说着 TCP
拿出了事先准备好的一张图,并投到了圆桌对面的屏幕上。
“大家请看,这是用户打开 https://blog.acohome.cn
时,通过我发送的一系类请求,我按域名进行了分类。” 说着 TCP
站了起来,走到屏幕前,指了指,屏幕上有如下一个表格
域名 | 请求数 |
---|---|
blog.acohome.cn | 33 |
cdn.bootcss.com | 4 |
code.jquery.com | 1 |
hm.baidu.com | 4 |
“大家请看,该页面内的资源来自 4
个服务器,却有 42
个请求。老大,目前我们实现 TCP
通道的策略是针对单个 HTTP
报文的,换句话说,就是每个 HTTP
请求,都会开启一个 TCP
通道,对吧?”
“嗯,没错。因为 HTTP
是无状态的。” 浏览器老大陷入了沉思,貌似知道了 TCP
所要阐述的内容了。
“一个 TCP
数据通道的建立和释放,需要进行三次握手和四次挥手。针对于上面的情况,需要进行 42
次这样的过程,但是这其中有很多次是发生在同一个客户端和服务端的。比如我需要与 blog.acohome.cn
所在的服务器进行 33
次相同数据通道的建立与释放,这会照成极大的资源浪费。以至于我在服务器的哥们对我有了不少的抱怨!”
“那说说你的解决方案吧!” 浏览器老大意识到了问题的严重性,确实这一块有较大的资源浪费。
长连接
“解决的方案其实简单,我不把数据通道销毁就好了,也就是长连接,针对相同域名,我每个单独建立一个通道,当然在请求多的情况下可以建多个。” TCP
自信满满的说道。
“嗯!不错的想法” 浏览器老大闭眼思考了一会,说道:“但是不能泛泛而谈,也有可能会出现需要及时释放的情况。这块容我想想该怎么实现!”
“嗯,确实会有特殊情况发生,需要好好考虑下。” TCP
也思考了一下。
“这样吧,我仔细想想!然后给你一个解决方案。” 说着浏览器老大站起身,说道:“那今天的会议先到这!”
keep-alive
大概过了 500ms
的样子,浏览器老大来到 TCP
的办公室。
“你提的确实是个好想法,但是是否保持数据通道不该由你来定,应该由上层的调用者来确定,就是 HTTP
,我顺便把他也叫过来了,你们商量商量。” 说着 HTTP
穿着白大褂走了进来。
“刚刚我听了,很不错的想法。老大,TCP
说的没错,我们这儿的请求基本上都是需要长连接的。要不就都这么处理吧!” HTTP
转向浏览器老大说道。
“不不不,你忘了上次我们主动加缓存出的问题了吗?如果开发者不需要长连接就麻烦了,这里不能写死!你接触开发者,所以在你的报文里加个特殊的字段吧,标志这个请求所在的域名是否需要长连接,然后把这个设置开放给开发者吧!” 浏览器老大想起了前几天定死缓存时发生的事情,慎重的说道。
“确实哈,那就和之前加缓存头一样?” HTTP
略微有点尴尬。
“对,字段就叫 Connection
吧,如果是 keep-alive
就是长连,如果是 close
就不长连,默认是长连,这样 OK
吧?”
“没问题!” TCP
和 HTTP
同时说道。
“那我顺便把这个字段提到 HTTP 1.1
规范中吧,刚好规范大会最近要开。” HTTP
补充道。
“嗯,让大家都用上也好 ~” 浏览器老大得意的说道,边说,边走了出去。
哎呦,不错哦
“TCP
牛啤啊!” 说着 HTTP
搂上了 TCP
的肩膀。
“那当然,风头不能都让你占了啊!”
“长连是好想法,但是请求的顺序不能乱哦,我给你一个报文,你要返给我一个,不然我可不知道怎么对应的!”
“哎 ~” TCP
叹了口气。
“怎么了?不能保证?” HTTP
显的有点慌乱。
“不是啊,我是能保证,但需要你一个一个给。”
“对啊,现在就是这样啊!你叹什么气?”
“其实吧,我有更好的方案,要不你了解了解?”
“真的?还有更好的?” HTTP
有点兴奋的说道。
管道化
“是有啊,但是和我服务的哥们讨论下来,实际的可行性可能有点问题。” TCP
面露尴尬。
“试试嘛,没准能行呢?”
“那我先说说实现原理哈。”
“嗯,你说!”
“首先,你直接把请求按顺序的给我,不需要等我给你的响应,直接把所有的请求按顺序给我就好,然后我把请求按顺序给到服务端,服务端在按顺序返回给我!” 说着 TCP
拿起纸笔画了起来。

“你看哈,最左边是现有的方式,中间是加了 keep-alive
的实现,右边呢是我刚提到的想法,我把最后这种实现叫做管道化,你看看。”
“管道化,有意思!牛皮啊!你给解释解释呗!我看你画的有点复杂。” HTTP
皱起了眉头。
“你把请求一开始就按顺序给我,由于通道是双向的,在建立连接后,我就可以边发送数据边接收数据,也就是说在第一个请求发出去后,我就可以开始接收第一个请求的数据了,也就是图中响应和请求出现交叉的地方。”
“原来你还有同时发送和接收的能力啊!确实,如果能实现的话,是够快的,那么问题在哪?”
“如果考虑到网络状况的话,问题就出现了!你想想如果说我刚发完所有的请求,第一个响应也收到了,但通道由于网络的原因,奔溃了!会发生什么情况?”
“按照正常处理就行啊,重建通道,再次发生!”
“问题就出在这!那第一个请求的响应怎么办?如果这个请求是 POST
请求,不就发了两次吗?要是这次多余的 POST
请求出了状况,那责任谁担?”
“emmmm
”
“还有就是即使网络状况好,就像刚刚画的,由于你给的请求是顺序的来,然后我顺序的发出去,那响应就是固定的顺序了,如果说第一个请求的响应服务器需要处理很长的时间,那后面的请求不也顺带着变慢了!”
“emmmm
”
“还不如我另开一个 TCP
通道来的快!”
“emmmm
”
“所以这个其实仅在特定的条件下,才会有效果,不然还不如不用!并且管道化单方面支持还不行,必须要和我服务器的哥们一起才行!”
“经你这么一说,确实啊,实际使用情况有限。兄弟,其实在设计缓存那一块时,我发现了一个真理!”
“什么真理?”
“把权限交给开发者!”
“什么意思?”
“我们这边其实并不能真正了解开发者的意图,因此能做的也有限,但如果你把是否使用管道化的权限交给开发者,在开发者确认能使用的情况下,就使用,这样就能在一个安全稳定的环境下,对性能进行提升了!”
“对哦,既然这个并不能针对到所有的情况,那么交给页面开发者就好了!真是个好想法!”
“还有你并不能直接接触开发者,那还是由我来给你吧。我把你的想法一并提到 HTTP 1.1
规范中,够意思吧!”
“好兄弟!”
算了,关了吧!
屏幕外:
“听说 HTTP 1.1
这次增加了一个叫管道化的技术,你了解过吗?”
“嗯,听说过,但网上对这个技术褒贬不一啊,并不能解决真正实际的问题。”
“怎么开呢?我想试试!”
“Chrome
下有个设置,你打开就行,你看在这!”
“嗯,打开了!”
“后端收到请求确实快了,一下子来这么多????”
“你有对你的服务器做过相关优化吗?”
“没有啊!”
“那还不如不开,你多试几次,看看是不是真的有提升?”
脚本一开,一顿操作,自动化测了 1000
次。
“emmmm
好像还不如不开...”
“...”
“算了,关了吧。”