徒手抓Bug的核心方法,两个词:折半和替换

2019-07-09 16:51发布

作为一个不精通二三十种编程语言的二十多年陈的码农,已经不满足于讲具体语言具体代码或具体工具的Debug,适用于一切领域的方法论才能更显逼格。下面是最近碰到的一个生动的小例子,用来展示Debug的核心方法。更曲折的故事以后再讲。

问题,以及这是个问题吗?

也学人玩自媒体,把自己网站上的文章搬到今日头条。有些文章又干又长,有十几张图。粘贴之后很多提示“图片上传失败”,每次大约只能上传5张图的样子。

简单搜了下:

看来是个已知问题。于是心里给出了一个积极的解释:嗯,今日头条很聪明,不鼓励太长太多图的文章。

这是谁的问题?

在继续向知乎、CSDN搬运的过程中(略有区别的是,用导入Markdown文本代替粘贴),也碰到了类似的问题。知乎人性化一点,可以重试(重试一般都能成功)。

无独有偶,看来这是个问题,而且不一定是今日头条的问题。

二分法及替换

对于Bug最简单、也是最重要的二分法是:我的Bug,别人的Bug。

我开始意识到:这可能是我方的问题!

对于Debug的过程而言,这其实也是最重要的一步。一旦意识到这有可能是自己的问题,解决问题的动力会高很多,并且马上就能想到办法。

那就是替换:换不同的电脑(不同的OS),换不同的浏览器。这些都没问题后,就换不同的网站:从简书搬运一篇同样的文章,图片能自动上传吗?

结果是正常的。

糟了,看来这确实是我的网站的问题。

顺便也可以推测复制粘贴时传递的是图片的URL,而不是图片本身,才有可能导致这样的问题。

第二次折半

可能的原因是网站的速度及并发数。下面是进一步的二分,看看问题可能出现在哪个环节以及对应的验证方法。

我的网站运行在Docker内,主机是Ubuntu,相关容器有两个:WordPress,和一个Nginx反向代理。

主机端可以怀疑的是最大连接数:

sysctl net.core.somaxconn
net.core.somaxconn = 512

对于我的小网站,512应该足够了,所以基本可以排除。

不管如何,Nginx大致位于主机和WordPress站点的中间位置,从它开始查起。

建立可替换的验证环境

另一个可替换的比较是在局域网和Internet上访问我的网站,看是否有差别。这样可以分析网速到底有多大影响。不管如何,建立一个可验证的最小测试环境都是重要的。

在网站临时目录放置比如64个文件,用于并发下载测试。下面是生成文件的脚本。测试文件简单地填0,用.dat作为后缀名,默认不会被web server压缩。

total=64
for i in $(seq 1 $total)
do
dd if=/dev/zero of=$i.dat bs=32K count=8
done

下面是下载的测试脚本:并行启动64个下载进程,然后每秒检测一次,看下载了多少个文件。

total=64
for i in $(seq 1 $total)
do
wget -q $url/$i.dat &
done
for i in $(seq 1 300)
do
sleep 1
count=$(ls *.dat | wc -l)
echo "Elapsed: $i s; Downloaded: $count"
if [ $count -eq $total ]; then
break
fi
done

第二次替换测试

在局域网内执行的结果是1秒内下载完所有64个文件。而在远程(美国)下载耗时4~5分钟,结果如下:

Elapsed: 3 s; Downloaded: 0
Elapsed: 4 s; Downloaded: 4
Elapsed: 5 s; Downloaded: 5
Elapsed: 6 s; Downloaded: 6
Elapsed: 7 s; Downloaded: 9
...
Elapsed: 268 s; Downloaded: 62
Elapsed: 269 s; Downloaded: 63
Elapsed: 270 s; Downloaded: 63
Elapsed: 271 s; Downloaded: 64

而远程下载单个大文件的速度接近50Mbps,据此推算下载64个256K的小文件需要的时间大约是3秒。

还有什么遗漏的环节?

在内网下载耗时很短,基本说明并发没有问题。而在外网下载耗时很长,基本可以算重现了问题。这样,暂时也不用去怀疑WordPress容器了(除非解决了外网耗时的问题后,还有问题)。

内外网的差别在于网络接入设备,包括无线路由器和光猫。因为光猫仅用来拔号上网,比较单纯,先不去怀疑它。

路由器的问题可能在于先天的性能不足,和后天的人为设置的限制。路由器的型号是华硕的AC1900P,使用梅林固件,硬件上按说不至于太差。而配置上,还是先检查连接数。

可以看到路由器的连接数是30万,是足够用的。而且,其它各方面状态都很正常。负载也不高。

谜底(Root cause)

还有什么?

难道是防火墙?难道是DoS保护?

尝试关闭DoS保护,结果如下:

Elapsed: 1 s; Downloaded: 0
Elapsed: 2 s; Downloaded: 9
Elapsed: 3 s; Downloaded: 43
Elapsed: 4 s; Downloaded: 57
Elapsed: 5 s; Downloaded: 60
Elapsed: 6 s; Downloaded: 63
Elapsed: 13 s; Downloaded: 64

可以看到,时间缩短了一个数量级。此时,再将我的站点上的十几张图片的文章粘贴到今日头条,全部上传成功。再开启DoS,又会上传失败或下载时间变长。

正反向都得以验证,于是水落石出。

结语

粘贴源自我站的有较多图片的文章到今日头条,出现大量图片上传失败,最终原因被证明是由于我站这方的路由器开启了DoS保护。可能是DoS保护的阈值太低(也许家用路由器的产品定位),导致并发访问速度慢。推测今日头条的服务器端超时设置也不会很长,于是被判为失败。

原因定位的过程主要是用折半查找来缩小范围,用局部替换来验证问题。这两个方法可以说是Debug的基础和核心。当然,用简化的方式搭建最小测试环境也很重要。

其它感想:

  • 在A上曝露的问题,原因可能来自B;
  • 不要遗漏故障链条上的任何环节;
  • 不要轻易去怀疑权威,如果对方是大量人使用的成熟系统,更要多从自己方面找原因。比如这个例子中,今日头条是亿万用户的在运营的系统,如果经常出现上传图片失败的问题应该是不可接受的;另一方面,我用的Nginx和WordPress是Docker Hub上的官方Image,也不至于超过10个并发访问就不行了。
  • Debug过程的两个里程杯:确认它是一个问题(包括可重现);确认它是自己的问题。

Debugging(或Troubleshooting)也是一项有成就感的工作,祝新老软硬件工程师Debug愉快!

文章来源: https://www.toutiao.com/group/6711539149897204238/