XIU2 / CloudflareSpeedTest

🌩「自选优选 IP」测试 Cloudflare CDN 延迟和速度,获取最快 IP !当然也支持其他 CDN / 网站 IP ~
GNU General Public License v3.0
18.24k stars 3.51k forks source link

修复某些情况下测速数值过大的问题 #290

Closed charSLee013 closed 1 year ago

charSLee013 commented 1 year ago

先说下 CloudflareSpeedTest的测速方法

  1. 创建一个 移动加权平均数 e

  2. 根据Timeout 切分成多个均匀的时间点,比如默认的时间点的间隔是 100ms

  3. 那么时间点分布就像是 0 .. 100 .. 200 .. 300 .. 400 .. 500

  4. 在超过时间点后,将此时间片内的增量数据添加到 e

  5. 有种特殊情况是当下载已经完成,还没到达下一个时间点的时候

  6. 会将 增量数量 / ((下个时间点 - 当前时间) / 时间片)

  7. 问题出在 下个时间点 - 当前时间,如果当前时间是 492ms, 而下一个时间点是 500ms,那么得出时间差是 8ms ,相当于计算的是 8ms 内增量数据

  8. 正确的算法应该是 当前时间 - 上个时间点 得出是 492 - 400 = 92ms ,计算的是92ms 内的增量数据

所以在距离下个时间点非常接近的时候,就会导致测试的数字膨胀过大

其他bug

还有段这样的代码

            if err != io.EOF { // 文件下载完了,或因网络等问题导致链接中断,则退出循环(终止测速)
                break
            }

按照原本的意思应该是当遇到 io.EOF 就退出才对,这也顺便改正过来了

XIU2 commented 1 year ago

你这比我分析的都明白。。。 这好几年前的代码,再加上我很久都没复习写过 Go,搞得我自己都忘得差不多了。。。

这个问题几年前就有人提过,这几年也陆续有几个人反馈过,但单靠文字交流很难排查问题,最后都不了了之了。 毕竟这个 BUG,看起来似乎比较看运气,你那边修复该问题时,是否有办法稳定复现(即测速出来的结果明显偏高)。

按照你的分析,该 BUG 主要会在以下情况时出现:

  1. 下载速度太快,还没到 10 秒(默认)就下载完成了
  2. 下载测速地址的文件太小,很快就下载完成了,导致出现上述情况
  3. 下载测速时间太长( -dt ),导致更容易出现上述情况

83

141

251

272

我在 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
XIU2 commented 1 year ago

另外,刚才翻 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 反馈的人去更新尝试~

hoockoo commented 1 year ago

感谢charSLee013,我更新新版本cfst后,貌似不能复现超速的问题了~

XIU2 commented 1 year ago

有人反馈出现下载速度 0.00 的情况,我排查后发现问题出在你提到的 "其他 BUG" 上。

if err != io.EOF { // 文件下载完了,或因网络等问题导致链接中断,则退出循环(终止测速)
    break
}

我仔细分析了下该代码的作用,发现其并不是写错了,而是本来就应该这样(!=),不过我的注释是明显写错了。。。 该注释并不是我最初写此处代码时加的,而是后来我复习代码时加的,结果因为“复习不认真”导致我当时理解错误,注释也因此而写错了,然后你修 BUG 时看到了但被注释给误导了。。。

最终我分析出来该代码的正确注释应该是这样:

if err != io.EOF { // 如果文件下载过程中遇到报错(如 Timeout),且并不是因为文件下载完了,则退出循环(终止测速)
    break
}

并非是我以前注释所写的什么 “文件下载完了balabal...”,如果是文件下载完了,那么该循环 for contentLength != contentRead {...} 也就会自行结束,压根不需要判断。

如果是其他报错,那么就直接跳出循环即可。 如果是下载测速超过总时长了,那么就没必要管剩下那点增量了,直接跳出循环。 如果是文件正好下载完了,那么就再计算并追加下剩余的增量后,正好也就结束了循环(循环尾回到循环头时判断了)。


总之,这算是一个因为 注释不规范+测试不完全 导致的 BUG 。。。 我测试时不够细心,没有全面测试,导致没注意到这个 BUG。。。

charSLee013 commented 1 year ago

感谢 XIU2 修正,我也忽略了超时或者其他错误的情况下应该退出的循环的