Closed charSLee013 closed 1 year ago
你这比我分析的都明白。。。 这好几年前的代码,再加上我很久都没复习写过 Go,搞得我自己都忘得差不多了。。。
这个问题几年前就有人提过,这几年也陆续有几个人反馈过,但单靠文字交流很难排查问题,最后都不了了之了。 毕竟这个 BUG,看起来似乎比较看运气,你那边修复该问题时,是否有办法稳定复现(即测速出来的结果明显偏高)。
按照你的分析,该 BUG 主要会在以下情况时出现:
-dt
),导致更容易出现上述情况我在 Issues 里找了找类似的反馈,发现它们都有个共同点,那就是这些人与 Cloudflare CDN 节点之间的网络质量都很好,随便测速一下都能轻松找到一堆最少几十 MB/s 的 IP,而正因为下载速度太快,下载测速地址的文件又偏小,导致更容易出现还没到 10 秒就把文件完全下载完了的情况,也就更容易触发该 BUG 了。
另外,其中有两个人提到了大量测速时遇到该 BUG,然后把这些异常的 IP 单独拿出来测速又正常了,似乎该问题在大量下载测速时更容易出现,而单独测速几个 IP 的话,又似乎难以复现。
不过我刚才专门找了两个小文件,来回进行下载测速,发现一次都没遇到,是我复现步骤不对?还是运气不好。。。
https://dl.feizhucache.ml/file/10MB.bin
https://zip.gitiray.my.id/5MB.zip
另外,刚才翻 Issues 时还找到了这个 #200 即在海外服务器上下载测速时,因为宽带太大、速度太快,导致在下载测速文件较小时,测速结果异常(明明有速度但显示为 0.00 或 NaN),当使用大文件 并 调低下载测速时间时(避免太快下载完成),才能正确显示下载速度(200~400 MB/s)。
我用目前 v2.2.0 版本与你修复后的 CloudflareST 的进行了对比,发现 v2.2.0 版本:
./CloudflareST -ip 104.16.68.38 -url https://speed.cloudflare.com/__down?bytes=200000000
× 下载测速结果异常,200 MB 文件,10 秒(默认)
./CloudflareST -ip 104.16.68.38 -url https://speed.cloudflare.com/__down?bytes=900000000
× 下载测速结果异常,900 MB 文件,10 秒(默认)
./CloudflareST -ip 104.16.68.38 -url https://speed.cloudflare.com/__down?bytes=900000000 -dt 2
√ 下载测速结果正常,900 MB 文件,2 秒(最多下载测速时间)
而你修复后的 CloudflareST 则不存在该问题,即使是 200 MB 10 秒 也能正确输出下载速度结果。
但奇怪的是,v2.2.0 版本用另一个下载测速地址却正常,不知道是不是 CF 官方下载测速地址的问题:
./CloudflareST -ip 104.19.8.12 -url https://dl.feizhucache.ml/file/10MB.bin
√ 下载测速结果正常,10 MB 文件,10 秒(默认)
更新(v2.2.2 修复了这点)!
知道为什么会这样了,那就是因为 CloudflareST 并没有考虑到像
https://speed.cloudflare.com/__down?bytes=200000000
这种实时生成的文件,也就是文件大小是未知的,导致明明下载完了,但软件不知道,于是还在计算下载量(直到超时为止),但因为是在海外大宽带服务器上测速,下载速度太快了,导致不到 10 秒(默认)就下载完成了,最终计算的结果要么明显偏低,要么直接显示为 0.00 。解决方法就是判断一下该下载测速地址文件大小是否是未知的,如果是未知的且文件已下载完成,那么直接终止测速,这样下载测速结果就是正常的了。
不过仔细对比后发现,同样是小文件,两个 CloudflareST 结果还是存在差异,修复后的下载测速结果往往都比 v2.2.0 版本的低一些(几MB/s ~ 几百MB/s 不等,即使放大到 300 MB 的文件也依然如此)。 看来在我本地网络环境下难以复现的问题,放到海外服务器这种大宽带的网络环境下(比较极端,毕竟在国内除非是加了钱的企业之类的宽带,否则不可能有家庭宽带跑这么快),就很容易复现了~
另外,根据反馈信息来看,似乎在 Linux 系统下该 BUG 更容易复现(即他们在路由器上经常遇到该问题,但在 Windows 系统下测速却没有遇到,不过我没有海外 Windows 服务器所以也无法验证这点。。。
既然复现成功并可以观察到结果修正了,那就合并吧,稍后我会发布新版本,也会通知上面那些 Issues 反馈的人去更新尝试~
感谢charSLee013,我更新新版本cfst后,貌似不能复现超速的问题了~
有人反馈出现下载速度 0.00 的情况,我排查后发现问题出在你提到的 "其他 BUG" 上。
if err != io.EOF { // 文件下载完了,或因网络等问题导致链接中断,则退出循环(终止测速)
break
}
我仔细分析了下该代码的作用,发现其并不是写错了,而是本来就应该这样(!=),不过我的注释是明显写错了。。。 该注释并不是我最初写此处代码时加的,而是后来我复习代码时加的,结果因为“复习不认真”导致我当时理解错误,注释也因此而写错了,然后你修 BUG 时看到了但被注释给误导了。。。
最终我分析出来该代码的正确注释应该是这样:
if err != io.EOF { // 如果文件下载过程中遇到报错(如 Timeout),且并不是因为文件下载完了,则退出循环(终止测速)
break
}
并非是我以前注释所写的什么 “文件下载完了balabal...”,如果是文件下载完了,那么该循环 for contentLength != contentRead {...}
也就会自行结束,压根不需要判断。
如果是其他报错,那么就直接跳出循环即可。 如果是下载测速超过总时长了,那么就没必要管剩下那点增量了,直接跳出循环。 如果是文件正好下载完了,那么就再计算并追加下剩余的增量后,正好也就结束了循环(循环尾回到循环头时判断了)。
总之,这算是一个因为 注释不规范+测试不完全 导致的 BUG 。。。 我测试时不够细心,没有全面测试,导致没注意到这个 BUG。。。
感谢 XIU2 修正,我也忽略了超时或者其他错误的情况下应该退出的循环的
先说下
CloudflareSpeedTest
的测速方法创建一个 移动加权平均数
e
根据
Timeout
切分成多个均匀的时间点,比如默认的时间点的间隔是 100ms那么时间点分布就像是
0 .. 100 .. 200 .. 300 .. 400 .. 500
在超过时间点后,将此时间片内的增量数据添加到
e
内有种特殊情况是当下载已经完成,还没到达下一个时间点的时候
会将 增量数量 / ((下个时间点 - 当前时间) / 时间片)
问题出在 下个时间点 - 当前时间,如果当前时间是 492ms, 而下一个时间点是 500ms,那么得出时间差是 8ms ,相当于计算的是 8ms 内增量数据
正确的算法应该是 当前时间 - 上个时间点 得出是 492 - 400 = 92ms ,计算的是92ms 内的增量数据
所以在距离下个时间点非常接近的时候,就会导致测试的数字膨胀过大
其他bug
还有段这样的代码
按照原本的意思应该是当遇到
io.EOF
就退出才对,这也顺便改正过来了