cnbatch / kcptube

同时支持传送TCP与UDP的KCP通道,附带端口跳跃的功能,以及FEC,自带中继服务器支持
BSD 3-Clause "New" or "Revised" License
95 stars 10 forks source link

大容量文件下载随机中断的问题 #14

Closed egg1234 closed 7 months ago

egg1234 commented 8 months ago

问题场景,下载 http://mirror.uoregon.edu/ubuntu-releases/20.04.6/ 的iso桌面安装映像(4.1GB),vps位于俄勒冈州,在vps上测试wget下载这个俄勒冈州立大学的托管网站映像没有任何问题,但是vps通过kcptube(有端口跳跃)转发gost的socks5代理,在境内用firefox浏览器设置代理进行下载就会出现随机的中断的问题(无论是否晚高峰),为了对比同一台vps安装hysteria转发gost的socks5代理,在境内用firefox浏览器设置代理进行下载没有任何问题,顺利下载4.1GB的iso文件

为了防止俄勒冈州立大学的托管网站有特殊问题,另外也使用了 http://mirrors.vcea.wsu.edu/ubuntu-releases/20.04.6/ 华盛顿州立大学的托管网站,然后在华盛顿州再开了另外一台vps,在vps上测试wget下载这个华盛顿州立大学的托管网站的iso桌面安装映像(4.1GB)没有任何问题,但同样这台vps通过kcptube(有端口跳跃)转发gost的socks5代理,在境内用firefox浏览器设置代理进行下载也出现随机的中断的问题(无论是否晚高峰),为了对比同一台vps安装hysteria转发gost的socks5代理,在境内用firefox浏览器设置代理进行下载没有任何问题,也顺利下载4.1GB的iso文件

但奇怪的是这些vps的kcptube转发gost的socks5代理,在境内连续1个多小时播放4k视频却完全没有中断或卡顿(无论是否晚高峰),也是使用firefox浏览器设置socks5代理进行播放的,只有下载大容量文件才会随机出现中断,而且以上所有测试在晚高峰及白天的早上低峰时间段都做过,情况一样,应该和拥挤没有关系

谢谢!

cnbatch commented 8 months ago

正在用哪个配置?(fast还是regular)

以及丢包率、延迟的状况如何?这两个很关键

egg1234 commented 8 months ago

kcptube版本20231028

下面是服务器的配置文件内容

mode=server kcp=fast5 inbound_bandwidth=500M outbound_bandwidth=500M listen_port=11000-11999 destination_port={} destination_address={} dport_refresh=20 encryption_password=password encryption_algorithm=AES-GCM keep_alive=10 ipv4_only=1

服务器gost监听 gost -L=:6000

下面是客户端的配置文件内容

mode=client kcp=fast5 inbound_bandwidth=450M outbound_bandwidth=50M listen_port={} destination_port=11000-11999 destination_address=www.mydomain.com dport_refresh=20 encryption_password=password encryption_algorithm=AES-GCM keep_alive=10 ipv4_only=1 mux_tunnels=5

[custom_input_tcp] :6000 -> 127.0.0.1:6000

晚高峰从境内ping那个俄勒冈州vps大概的延时及丢包 --- ping statistics --- 377 packets transmitted, 340 received, 9.81432% packet loss, time 376969ms rtt min/avg/max/mdev = 204.458/219.534/318.742/12.233 ms

服务器及客户端的ubuntu 20的/etc/sysctl.conf文件里面已经加了下面内容 net.core.rmem_max = 3500000 net.core.default_qdisc = fq net.ipv4.tcp_congestion_control = bbr

cnbatch commented 8 months ago

感谢反馈,排查后发现几个星期前优化原版 KCP 性能时,对数据包 ACK 的部份处理不当(几个星期前使用原版 KCP 的版本没这个 ACK 的问题)。这个部份现在已经修复好了。

另外需要注意的是,无论是原版KCP还是现在优化过的,主要目标仍然是降低延迟,而非传输大流量(README.md 开头就提到过)。其中 README.md 底部就提到过原版 issue 区的《如何避免缓存积累延迟的问题》,意思就是流量过大会缓存区爆满会导致延迟越来越大。再加上 kcptube 本身在 keep_alive 过期后(过期时间 = 内置过期阈值 31 秒 + 用户设置的 keep_alive 时长)仍收不到任何数据包时,会认为连接受阻、失效,于是就强制断开连接。所以丢包率越高的环境,就越容易因为等待时间过久而间接导致 kcptube 断线。

目前能够做的也就只有尽量缓解,比如使用更激进的 fast1 或 fast2,以及把 keep_alive 的时间延长一点。

更强力的缓解措施是内置 FEC 机制,不过这并非立即能够做得到,要改的地方很多,并不简单。 KCPTUN 和 UDPSpeeder 就内置了 FEC 机制,用的都是 Reed-Solomon 算法,然而 KCPTUN 只支持转发 TCP 数据包(有人提议加上 UDP,作者不愿做),UDPSpeeder 只转发 UDP 数据包。 他们的创作时间都比我早很多年,但都不做同时支持 TCP + UDP + FEC,所以短期内我应该也没什么好办法了。

egg1234 commented 7 months ago

想请教 fast1, fast3, fast5那个是更激进?按照我理解应该是fast5?因为好像fast5重传是4,而fast1重传是2?

谢谢!

cnbatch commented 7 months ago

kcp_resend 数值越小,就越激进。 kcp_resend 指的是 KCP 内部的 fastresend 变量值,表示跨越了指定次数后就不再等待,直接重传。 数值越大,等待时间就越长。

刚刚在 Wiki 页面增加了简单版的模式解读: https://github.com/cnbatch/kcptube/wiki/%E5%8F%82%E6%95%B0%E5%88%97%E8%A1%A8#%E6%A8%A1%E5%BC%8F%E8%A7%A3%E8%AF%BB%E7%AE%80%E6%98%93%E7%89%88 不但把列表中对应的原变量名都列了出来,也给出了简单说明,可以参考着选择

egg1234 commented 7 months ago

谢谢解惑!

使用20231104测试,如果按照上面的配置不变,下载那个大文件中断的时间更快,大概10秒左右就一定中断下载了,比旧版本还快,同样的不影响播放4K视频

然后把上面的配置文件改了两个地方,更改为kcp=fast1,删除keep_alive=10这一项参数,但一样大概10秒左右就一定中断下载,反正比20231028版的情况还差,也同样的不影响播放4K视频

上面测试都是在早上带宽比较空闲时候做的

下面是延时及丢包情况,比晚高峰好非常多 --- ping statistics --- 398 packets transmitted, 398 received, 0% packet loss, time 386079ms rtt min/avg/max/mdev = 180.924/184.653/248.615/14.153 ms

cnbatch commented 7 months ago

用的是浏览器还是curl?

如果需要下载文件,其实可以直接指向服务器的端口,无须再一次中转: https://github.com/cnbatch/kcptube/wiki/%E6%9B%B4%E5%A4%9A%E5%85%B7%E4%BD%93%E7%A4%BA%E4%BE%8B 按照这里的做法,对于高延迟高丢包的线路,curl会在10秒左右的时候见到速度稍微下降(可能会降为0),随后速率再次上升,如此波动一两次之后,传输率会稳定下来。

加个 blast=1 效果更好。

对于浏览器,既然都已经用着socks5了,在当前连接传文件或许会更简便。

egg1234 commented 7 months ago

下载是使用客户端局域网的另外一台windows机器,firefox浏览器设置socsk5代理指向ubuntu20的客户端端口这样来下载的,其实也尝试了http代理方式,因为gost同一个监听是混合了socks5及http方式的,但是http代理结果是一样的

如果指向服务器端口的话,等于每次不同目的地服务器都必须改一下客户端配置文件进行指向,这样比较麻烦

egg1234 commented 7 months ago

测试了20231112版,情况一样,但是这次有一个现象,下载速度一开始会达到峰值,然后大概是每秒下降速度值,大概4-5秒后中断,每次都一样,感觉是kcptube与代理程序中间通信的缓冲区满了,然后kcptube中断与代理程序的通信

但播放4k甚至8k视频都永远没有任何卡顿,有一个猜想是播放视频的带宽是固定的,而且都在kcptube的缓冲及流量控制机制的容忍范围内,而下载文件是尽力用满带宽,可能就超出了kcptube的容忍范围,但kcptube没有像其他传输工具(如hysteria,juicity等)的端口转发一样有一个流控机制与代理程序沟通,或沟通的机制不理想,导致持续传输峰值带宽的流量会中断

cnbatch commented 7 months ago

从170ms延迟到330ms延迟的线路都试了下,在开启mux_tunnels的时候,fast3和fast4及往后比较容易出现这种情况,fast1和fast2很难出现

我试验的方式:

graph LR;
    A[Python3 HTTP Server]-->B[kcptube Server];
    B-->C[kcptube Client];
    C-->D[curl];
graph LR;
    A[Target Website]-->B[SS Server];
    B-->C[kcptube Server];
    C-->D[kcptube Client];
    D-->E[SS Client];
    E-->F[Browser];

即使是达到10%的丢包率,fast1~fast2模式都试不出断流的情况,速度降为0倒是出现过很多次,一般两秒左右后就恢复了。

fast3~fast4在这种丢包率+300ms高延迟的情况下,会有几率出现断流。往后的配置,几率会更高。如果碰到连续丢包,那就很容易断。

对于TCP连接而言(无mux_tunnels),能够造成连接断掉的情况只有3种:

  1. 外部TCP主动断开
  2. TCP超时(这是操作系统协议栈的事情)
  3. keep alive 检测包超时

任一情况成立都会断开

对于mux_tunnels,能够造成断连的情况只有2种:

  1. keep alive 检测包超时
  2. 当前 KCP 连接超过31秒收不到任何数据

同样,任一情况成立都会断开

其中,keep alive超时断开,会主动告知对端。检测到超时的既可以是server侧,也可以是client侧。目前的流程是:

graph LR;
    A[kcptube Local] -- keep_alive -->B[kcptube Peer];
    B-- keep_alive_response-->A;

所以,如果这中间阻塞太严重,是会导致连接断开的。 以前的做法只是单向发送,于是对面程序崩溃了自己仍然不知道,最后改成现在这样。

对于keep alive的情况,稍微灵活点的方案是,我把断连判断改成“keep alive检测包超时”且“当前 KCP 连接超过31秒收不到任何数据“同时成立才算作真正的keep alive超时,可以有所缓解。

至于浏览器看视频不会断,原因是浏览器从多台服务器获取数据时并不会只走单条mux tunnel(除非mux_tunnels数值低到只有1或2),而是分布于多条tunnel,那就没那么容易造成阻塞。

egg1234 commented 7 months ago

已经测试过删除mux_tunnels参数,然后浏览油管网站非常慢,根本不能播放视频,哪怕分辨率很低都不行,只在转圈,下载更不用说了,网站上去都非常慢

如果配置mux_tunnels=10,测试结果与mux_tunnels=5没有任何区别

现在看起来这个问题没有任何头绪,先把这个issue关了,之后有进展再reopen吧

cnbatch commented 7 months ago

这个 bug 终于找到了,不启用 mux_tunnels,在高延迟(300ms+)、超高丢包率(30%)的情况下,下载大量小文件(小于1M)时多次复现。

原因是 Server 模式立即关闭连接导致的,这时候还有少量数据来不及传回客户端。新版本修复了这个 bug。

虽然 mux_tunnels 未发现有这种情况,但从流量图表发现速率经常大起大落。起因是 mux_tunnels 模式自身的缓存数据转移至 KCP 缓存时的方式如同中小学数学题“一边排水一边灌水”,满了就停,有余量就放。两层缓存都这样。因为每次“排放”的数据量的差别可以很大,于是 TCP 的流控也会被弄得大起大落。现在新版本改成了“KCP 缓存完全排空才能接数据”的方式,表现相对稳定多了。

egg1234 commented 7 months ago

同样使用上面的配置,替换成20231126版测试,情况没有改变

wangyu- commented 6 months ago

KCPTUN 和 UDPSpeeder 就内置了 FEC 机制,用的都是 Reed-Solomon 算法,然而 KCPTUN 只支持转发 TCP 数据包(有人提议加上 UDP,作者不愿做),UDPSpeeder 只转发 UDP 数据包。 他们的创作时间都比我早很多年,但都不做同时支持 TCP + UDP + FEC,所以短期内我应该也没什么好办法了。

UDPspeeder wiki里面有一篇文章有讲,怎么kcptun和UDPspeeder并联,同时支持UDP和TCP。 U

DPspeeder不做tcp是因为强调不同软件配合,这样你对哪个功能不满意都可以换掉。 比如kcptun+udpspeeder+ss, 你可以换掉kcptun也可以换掉udpspeeder也可以换掉ss。 如果所有功能都做到一个软件里,没办法轻易替换掉其中的一部分,你只能求作者开发/改进。

cnbatch commented 6 months ago

KCPTUN 和 UDPSpeeder 就内置了 FEC 机制,用的都是 Reed-Solomon 算法,然而 KCPTUN 只支持转发 TCP 数据包(有人提议加上 UDP,作者不愿做),UDPSpeeder 只转发 UDP 数据包。 他们的创作时间都比我早很多年,但都不做同时支持 TCP + UDP + FEC,所以短期内我应该也没什么好办法了。

UDPspeeder wiki里面有一篇文章有讲,怎么kcptun和UDPspeeder并联,同时支持UDP和TCP。 U

DPspeeder不做tcp是因为强调不同软件配合,这样你对哪个功能不满意都可以换掉。 比如kcptun+udpspeeder+ss, 你可以换掉kcptun也可以换掉udpspeeder也可以换掉ss。 如果所有功能都做到一个软件里,没办法轻易替换掉其中的一部分,你只能求作者开发/改进。

想不到UDPSpeeder作者主动出现,请接受我的感谢,多年前我也在用UDPSpeeder。

我造KCPTube的最初动力,就是来自受困于较新版本的OpenVPN经过AEAD加密后死活不接受乱序包造成的大麻烦。Replay-window设到1024仍然没用。(我自己的UDPHop对此情况一样没用。)KCP本来是可以确保顺序收包的,然而KCPTUN偏偏不支持转发UDP。

第二个动力是脱离Linux完整转发 ss。我日常使用的是FreeBSD + Windows的组合方式(已经在其他issue提到过),ss和OpenVPN的数据都在BSD和BSD之间、BSD和Windows之间流动。

第三个动力就是端口跳跃,主要受到v2ray的启发。然而v2ray及后续衍生版对于UDP/KCP做底层传输方式的兴趣并不大,多年都没怎么更新KCP的组件。

三个动力、需求的叠加,没有现成的软件可以满足,只好自己造一个了。

至于出现的bug,其实很多时候我也不清楚为什么会出现,只好靠猜测,就连FEC也是。最近这些版本的FEC也是为了解决bug而引入的。 虽然后来我发现bug与FEC关系不大,似乎是因其他原因造成的(疑似新连接抢占满载通道导致该通道所有连接被迫长时间暂停),并且针对这个猜测做了新的修改。(但还是实在不好意思再麻烦issue作者以及其他人做测试,万一发现又搞错了那我真的越来越尴尬)

egg1234 commented 6 months ago

同样使用上面的配置,替换成20231202版测试,情况没有改变 但播放4k及8k视频完全没有任何卡顿

cnbatch commented 6 months ago

这就十分奇怪了,会不会是gost的问题? 我用的是xray-core里面的shadowsocks,同时下载两个文件都不会断,v2ray的shadowsocks也试过,同样没断。

graph LR;
    A[KCPTube Client]<-->B[xray-core as shadowsocks client];
    B<-->C[xray-core as shadowsocks server];
    C<-->D[KCPTube Server];
egg1234 commented 6 months ago

其实我已经用了xray-core 1.8.4版,因为平时已经是需要使用xray-core的,只是服务器多开了另外一个进程监听socsk5,主要是考虑到kcptube的端口转发已经有加密了,所以客户端也是直接xray-core 1.8.4 outbound socsk5到服务器,但无论是gost还是xray-core,测试结果都是一样的,监听及转发ss倒是一次都没有试过