这个客户问题消耗了我3天时间,有必要记录分享一下。
    问题场景:客户集群环境,访问FVS模板,模板内有体积较大的三维模型文件(8M - 40M不等),概率出现模型下载失败:Network看到200状态码,但下载内容不全,比如10M的模型下载到6M就停止下载了,导致前端部分模型渲染不出来。控制台可看到如下错误:
    企业微信截图_16680603973719.png
    问题原因:经过各种试错以后,发现这是一个通用场景 —— 即弱网环境下,http请求在进行过程中,会概率失败。当然正常情况下,这个失败我们是能看到错误信息的。这里Network显示200主要是因为走了集群转发。
    问题复现:自定义一个HTML,使用img标签加载20M的图片,放到tomcat环境访问,利用浏览器Network的节流功能模拟弱网环境,测试:

    网速 成功/失败 截图
    0.5/8MB/s 1.8min 失败
    全部完成应该需要5.6min
    image.png
    1/8MB/s 2.8min 成功
    全部完成应该需要2.8min
    image.png

    因为浏览器有并发(同时下载多个图片会共用带宽),带宽会影响,假设并发数量 = 6,测试并发场景
    6 / 8 MB是否成功

    网速 成功/失败 截图
    1/8MB/s 失败
    (预计就是失败,因为6并发)
    image.png
    6/8MB/s 并发的6个全部成功
    预计和单图片1/8MB一样,成功,2.8min左右全部完成
    image.png

    失败原因:TCP为了保证数据传输的完整性、有序性,通信双方需要不断交流我发了多少,我收了多少,看有没有丢包、乱序等情况。为了防止大量数据传入另一方不能及时处理,所以有”窗口大小”的限制。即:我最多只能接收(缓存)”窗口大小”的数据,超出了以后,发送方就要等一等。同时发送方也会不断发长度为0的消息和接收方确认:你现在的窗口大小是多少,是不是能接收了。当确认N次,或等待N时间后,仍然没有回应,TCP会自动中断,导致失败。
    这就好像2个人在打电话,一边信号特别差,我说了20句喂喂喂,在不在,你都不回应,我就挂电话了。
    分析过程:使用WireShark抓包看TCP连接发生了什么,最后开始进行上面的测试,得出上面的推断。
    企业微信截图_16682425053718.png
    服务器连续发送N个数据包,客户端一直没响应,最后服务器知道自己不能在发送了(超出TCP窗口限制);
    如果之后客户端能及时释放窗口响应,2者通信继续,但如果不能,则服务端会主动断开TCP连接并且不通知客户端(你都不响应了,还通知你干什么)
    企业微信截图_16682427143170.png


    淦!没想到还有续集……
    原本以为到这问题就解决了,为表诚意,华锋周一还去了客户现场一起调试,看看是不是网速正常就不会有问题。万万没想到,现场调试,客户50Mb/s(约6MB/s)的下载网速,仍然大概率出错!
    而且不经过集群,单节点访问没有问题!难道绕了一圈,还是Traefix这个集群配置的问题?……
    最后又迎来了第二个主角:http2.0…… Traefix只支持http2.0,不支持http1.1
    http2.0有个很大的特点:多路复用
    http1.1 - 1个http请求需要1个tcp连接,浏览器为了避免一个页面建立太多tcp连接,做了6并发的限制 —— 最多建立6个连接,也就是我们从network里看到的http请求6并发;
    http2.0 - 1个tcp连接可以给多个http请求同时使用(多路复用),所以我们network看http2的网站,是能看到很多http请求在同时进行的。
    http2.0的好处是很明显的:在带宽、服务器资源足够的情况下,高并发请求的性能可能会比http1.1好很多很多。但是,我们考虑一个极端场景:带宽一般、高并发。原本的6并发限制还能作为一个防御屏障让小水管勉强运行下去,而到了2.0打破了这个限制,完全起到了反作用。

    TCP 的队头阻塞并没有彻底解决 TCP 为了保证可靠传输,有一个“超时重传”机制:丟失的包必须等待重传确认。HTTP2 出现丢包时,整个TCP都要等待重传,那么就会阻塞该TCP 连接中的所有请求。 多路复用导致服务器压力上升 多路复用没有限制同时请求数。请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 多路复用容易 Timeout 大批量的请求同时发送,由于 HTTP2 连接内存在多个并行的流,而网络带宽和服务器资源有限,每个流的资源会被稀释,虽然它们开始时间相差更短但却都可能超时。

    很遗憾,用户刚好符合这个情况:20+三维模型文件同时请求,6.8MB/s左右的下载速度。而直连单节点为什么好的,因为单节点直连tomcat,仍然使用http1.1协议。
    最后,在Chrome浏览器上找到一个禁用http2.0的参数,暂时规避此问题。
    但是,http2.0的这个特点,在带宽足够的情况下,无疑是一个性能很大的提升,虽然带宽不足的情况下反而起到了反效果,但也掩盖不了它突破6并发限制后带来的性能提升。我们的frm和fvs都有很多高并发请求场景,而且http2.0已经是很早以前的技术了,或许已经有竞品在这块压制我们了。