Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Feb 11, 2023
Merged

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

merged 2 commits into from
Feb 11, 2023

Conversation

charSLee013
Copy link
Contributor

先说下 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
Copy link
Owner

XIU2 commented Feb 11, 2023

你这比我分析的都明白。。。
这好几年前的代码,再加上我很久都没复习写过 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
Copy link
Owner

XIU2 commented Feb 11, 2023

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

@XIU2 XIU2 merged commit f5ce273 into XIU2:master Feb 11, 2023
@hoockoo
Copy link

hoockoo commented Feb 11, 2023

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

@XIU2
Copy link
Owner

XIU2 commented Feb 12, 2023

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

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

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

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

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

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

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


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

This was referenced Feb 12, 2023
@charSLee013
Copy link
Contributor Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants