V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
supermoonie
V2EX  ›  Java

Connection: keep-alive 迷一样的东西

  •  
  •   supermoonie · 2020-09-09 23:51:03 +08:00 · 3224 次点击
    这是一个创建于 1317 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用 netty 写了一个 http & https 代理,在将服务器响应的发送到客户端(浏览器)后,如果不手动关闭代理与服务器的连接以及客户端的连接,netty 就会重用之前的连接,这样的话,整个网站(比如 youtobe )的流量都只通过一个连接通道进行传输,看视频卡得一批。当响应发送到客户端后就关闭 Channel,哇,整个世界都舒服了,网速直接满载,连接的通道也多了,再加上二级代理,youtube 1080p 妥妥的

    21 条回复    2020-09-11 12:13:53 +08:00
    ysc3839
        1
    ysc3839  
       2020-09-09 23:59:55 +08:00 via Android
    这是你网络的问题吧?针对单连接进行了限速。如果是 HTTP/2 的话,你这种操作就没用了,一个服务器的所有请求都是使用单个连接的。
    est
        2
    est  
       2020-09-10 00:18:58 +08:00 via Android
    @ysc3839 这个是 chrome 的特性。h2 协议本身可以多路复用 m:n 来并发传输 chunk
    supermoonie
        3
    supermoonie  
    OP
       2020-09-10 00:49:19 +08:00
    @ysc3839 限速应该不会有,因为网络在测试期间没有变动,而且测试了很多次。HTTP/2 的话会进行降级处理。单个连接是没问题,如果 keep-alive  的话,新的请求就会使用现有的连接,那么这个连接的传输能力岂不是就会很慢吗?现在通过手动关闭,就有机会创建多个连接,是不是就会快了很多?以上只是猜想,我还需要更多的测试进行验证才能找到问题所在
    supermoonie
        4
    supermoonie  
    OP
       2020-09-10 00:56:00 +08:00
    @est 看了下协议的版本,是 HTTP/1.1,应该是 Chrome 对 keep-alive 做了处理,现在就测试的现象来看,主动关闭客户端( Chrome )的通道,网速就上去了,可能是我代理服务器的连接重用机制需要调整,我去查一下 netty 关于连接复用的处理细节再测试看看
    Mohanson
        5
    Mohanson  
       2020-09-10 07:03:54 +08:00 via Android   ❤️ 1
    估计你处理完一个 http 请求后没有接着从该 tcp 通道继续读取 http 请求,导致浏览器重用通道后发的请求会喂了狗然后等待几秒时间后重试,和 persistent connection 没关系。另外 http 代理的 persistent connection 在 firefox 上有 bug
    supermoonie
        6
    supermoonie  
    OP
       2020-09-10 07:52:20 +08:00
    @Mohanson 应该不是没有继续读取 http 请求的问题,因为 netty 每次的 channelRead 事件,我都有日志打印跟踪,最终都会与服务器的连接通道发出去,还是觉得 Chrome 在处理 keep-alive 的时候,有点迷。如果不主动关闭 Chrome 的 channel,Chrome 就会一直转圈圈,也不会失败,而是等很久才加载出来。现在代理的线程池配置是处理客户端 channel 的固定 16 个线程,处理服务器端 channel 也是固定 16 个线程,所以我在想是不是因为 channel 重用导致线程池被耗尽了
    domosekai
        7
    domosekai  
       2020-09-10 09:03:45 +08:00
    youtube 的视频(googlevideo)本来就是单连接,打开 F12 看看卡在哪儿了
    supermoonie
        8
    supermoonie  
    OP
       2020-09-10 09:21:41 +08:00 via iPhone
    @domosekai 卡在了 pending ……
    domosekai
        9
    domosekai  
       2020-09-10 11:16:29 +08:00   ❤️ 1
    pending 表示现有连接被占用,那我的猜测和#5 类似,你的代理因为某种原因让 chrome 无法复用连接,导致卡死超时后再重新连接,虽然你主动断开看上去也可以,但不一定适用于其他网站,我试了下 youtube 的视频在 chrome 使用代理和直连的情况下都是单连接复用
    supermoonie
        10
    supermoonie  
    OP
       2020-09-10 18:40:48 +08:00 via iPhone
    @domosekai 待我今天晚上再验证下
    supermoonie
        11
    supermoonie  
    OP
       2020-09-10 22:09:18 +08:00
    @ysc3839
    @est
    @Mohanson
    @domosekai

    感谢各位,确实是代码的问题,在处理 EmptyLastHttpContent 的时候有客户端连接状态的判断,如果没建立连接的话,EmptyLastHttpContent 就会被丢弃掉,导致发送到目标服务器的请求迟迟不能结束,所以造成了客户端请求的 pending 。
    arloor
        12
    arloor  
       2020-09-10 22:24:45 +08:00
    按道理来说,youtube 现在应该是 http2 的了
    即使走了 http 代理,也会使用 connect 隧道,在这种情况下,仍然应该是 http2

    另外,你的这个项目应该可以在一定程度上对比下这个 https://github.com/arloor/HttpProxy

    既然你提到 EmptyLastHttpContent,应该和这个项目的实现差不多
    supermoonie
        13
    supermoonie  
    OP
       2020-09-10 22:51:35 +08:00
    @arloor youtube 现在确实是 h2 的协议了,不过代理会对其进行降级,目前还没深入研究,后面再细细研究下 h2 。确实和那个项目差不多,不过我现在写的提供了 HttpRequest 、HttpResponse 的拦截器,动态二级代理支持,黑白名单,远程及本地映射以及即将实现的网络信息统计、自定义 DNS 、限速、vmess 协议、ss 协议等。另外基于拦截器做了一个类似 Charles 的单页面应用,基本上和 Charles 的功能一样,只不过我把请求和响应保存到 sqllite 数据库中了,可以进行查询。另外的打算可能是做插件管理,比如某盘的嗅探多线程下载插件。感觉可以做的很多。。。
    arloor
        14
    arloor  
       2020-09-10 23:01:24 +08:00
    @supermoonie 其实我觉得还是 http 代理本身比较有意义,其他的其实并不是很有意义

    友情提醒一下,代理这种场景中需要注意控制背压,不然会有 outofDerectMemory
    supermoonie
        15
    supermoonie  
    OP
       2020-09-10 23:08:39 +08:00
    @arloor 现在还没遇到过,等做完了做下各种网络测试。GlobalChannelTrafficShapingHandler 这个 handler 应该能解决很多问题,特别是请求堆积造成的内存泄漏
    monkeyWie
        16
    monkeyWie  
       2020-09-11 07:42:08 +08:00 via Android
    @supermoonie 跟我这个很像啊,另外还实现了 https 的中间人攻击,https://github.com/monkeyWie/proxyee
    supermoonie
        17
    supermoonie  
    OP
       2020-09-11 09:11:44 +08:00 via iPhone
    @monkeyWie 哎呦,大佬大佬,确实是参考了你的那个项目,没想到碰到作者了,只不过我重新写了一遍,加了一些以及需要的功能,另外用 vue 写了一个抓包的界面🤣
    monkeyWie
        18
    monkeyWie  
       2020-09-11 09:28:43 +08:00
    @supermoonie 哈哈,巧了,抓包最麻烦的地方就是要处理大响应,比如上传文件和下载文件,搞不好就 OOM 了😄
    supermoonie
        19
    supermoonie  
    OP
       2020-09-11 10:07:48 +08:00
    @monkeyWie 大的请求和响应,是不是可以通过 Content-Length 判断下,然后超过一定的阈值,先序列化到本地文件中,再通过 Buffer 分块读取,这只是我的猜想,不知道可不可行🤣
    monkeyWie
        20
    monkeyWie  
       2020-09-11 10:40:29 +08:00
    @supermoonie 我也是这样考虑的,不过 chunked 编码的还要特殊处理下,因为拿不到 Content-Length🤣,还有那个 h2 的如果是 connect 隧道的话应该是不会降级的
    supermoonie
        21
    supermoonie  
    OP
       2020-09-11 12:13:53 +08:00
    @monkeyWie 能拿到 FullHttpRequest 以及 FullHttpResponse 中的 content 吧,然后根据这个 content 获取 content-lenght,可还行?等我这周末测试下大的请求 /响应,看看能不能找到解决方法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1261 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:54 · PVG 01:54 · LAX 10:54 · JFK 13:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.