互联网上有关错误有时是如何完全令人难以置信的表现的故事的最后一部分。第一部分,第二部分。
小SSH(有时)无法
这是一个有关我最幸运地参与其中的最令人兴奋的错误搜寻之一的故事。
在我工作过的AdGear Technologies Inc.,一切都保存在SSH上。我们将其用于管理,监视,部署,日志收集,甚至用于实时流媒体。该协议健壮可靠,具有本地Unix工具的可预测性,并且可以正常工作。
但是,一旦没有任何具体时间或主持人的来信告诉我们该协议无效。
超时
将日志文件发送到蒙特利尔数据中心时,伦敦数据中心中的计算机随机崩溃。此任务是定期从Cron运行的,失败本身表现为:
- Cron电子邮件报告了SSH问题。
- 有时会冻结。
- 有时它退出时没有超时错误。
- 在内部健康检查中,Nagios警告说蒙特利尔缺少数据。
我们登录了伦敦的汽车,手动启动了该命令
push
,该命令成功运行。我们把它归结为一个临时的网络问题。
超时时间
但是,崩溃不断重复发生。每天一次,每天几次,星期五早上,一个小时几次。很明显,情况正在恶化。我们继续手动推送文件,直到找出问题所在。
伦敦和蒙特利尔之间有17跳。我们创建了一个数据包延迟和丢失配置文件。事实证明,在几跳中丢失了1-3%的数据包。我们与伦敦数据中心的运营部门一起申请了重新路由。
在伦敦人检查数据包丢失信息时,我们开始寻找从伦敦到第二个伦敦的随机超时蒙特利尔的数据中心。这条路由上的跃点是不同的,而不是丢失数据包的跃点。我们认为丢失不是主要问题,此外,伦敦人还报告说他们无法再现丢失的数据包或超时,并且一切看起来都很好。
启示录
在手动转发不良的Cron消息时,我们注意到了一个有趣的模式。文件要么成功地高速传输,要么根本不传输,并在超时时挂起。没有任何文件以低速成功下载的情况。
通过从方程式中删除大部分数据,我们能够使用简单的香草SSH重新创建脚本。在伦敦数据中心中,“ SSH mtl-machine”服务器要么立即完成任务,要么挂起,无法建立连接。惊喜开始增加。
这些包去哪儿了?
我们三次检查了蒙特利尔的SSH服务器配置和系统:
- DNS服务器快速响应。
- 反向DNS查找区域已被禁用。
- 客户端连接的最大数量足够大。
- 我们没有受到攻击。
- 通道未堵塞。
此外,即使某些事情不起作用,当与蒙特利尔的两个不同数据中心一起工作时,我们也会观察到冻结。此外,我们的非伦敦数据中心已与蒙特利尔成功通信。也就是说,问题与伦敦有关。
我们运行tcpdump并查看了软件包。我们对使用Pcaps获得并加载到Wireshark中的一般动力学和数据感兴趣。我们看到了丢包和重传的迹象,但是一切都很少,也不必担心。
然后,我们分析了在SSH通信成功建立的情况下的整个连接,然后-分析了在SSH通信停止的情况下的连接。
当伦敦与蒙特利尔的联系陷入僵局时,我们得出以下结论:
- 建立TCP连接正常。
- 服务SSH信息来回发送。必要时,会有正常的TCP ack数据包。
- 从伦敦发送了特定的包裹,并在蒙特利尔收到了包裹。
- 同一封包从伦敦重新发送了几次,并在蒙特利尔收到。
- 蒙特利尔根本无法回答这个问题!
目前尚不清楚为什么蒙特利尔没有回应(因此,伦敦再次发送了数据)。由于第4层协议已挂起,因此连接已挂起。更令人兴奋的事实是,如果您中断在伦敦重复发送的SSH发送并立即将其重新启动,则它将成功运行。在这种情况下,tcpdump表示蒙特利尔已收到该软件包并做出了回应,并且工作继续进行。
在伦敦的SSH客户端上,我们启用了详细调试(
-vvv
),并且在这些日志条目之后,连接已挂起:
debug2: kex_parse_kexinit: first_kex_follows 0
debug2: kex_parse_kexinit: reserved 0
debug2: mac_setup: found hmac-md5
debug1: kex: server->client aes128-ctr hmac-md5 none
debug2: mac_setup: found hmac-md5
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: SSH2_MSG_KEX_DH_GEX_REQUEST(1024<1024<8192) sent
debug1: expecting SSH2_MSG_KEX_DH_GEX_GROUP
我们在“ SSH挂起SSH2_MSG_KEX_DH_GEX_GROUP”上进行了搜索,并获得了很多结果,从Wi-Fi问题到Windows中的TCP错误以及丢失TCP片段的错误路由器。 LAN的解决方案之一是计算路径的MSS,并将此值设置为路径两端的MTU。
我一直将伦敦服务器上的MTU从1500降低-直到我达到576的神奇值时,它才有用。在那之后,SSH不再挂起。我当时正在运行带有SSH循环的脚本,并且如果需要,可以通过将MTU返回1500来引起超时,或者通过设置576来消除它们。不幸的是,这些是公共广告服务器,并且全局将MTU分配为1500不能解决问题。但是,上面已经提到过,数据包的分段或重组过程可能在某处中断了。
让我们回到使用tcpdump检查接收到的数据包:没有碎片的迹象。接收到的数据包的大小与发送的数据包的大小相同。如果某个东西将字节576+上的数据包弄成碎片,则说明某东西已经成功地重新组装了它。
一闪一闪,曲线星
在深入分析时,我查看了完整的数据包转储(
tcpdump -s 0 -X
),而不仅仅是标头。当比较成功发送的魔术包和失败发送的包时,除了TCP / IP标头外,我发现几乎没有区别。但是很明显,这是TCP连接上的第一个数据包,其中包含足够的数据以通过576字节标记。以前的所有软件包都小得多。
比较失败的分发中的相同数据包,以它离开伦敦到达蒙特利尔的形式,我的目光注视着某些东西。对于一些微妙的东西,由于疲劳(我是星期五晚上),我把它甩开了。但是经过几次更新和比较,我不再幻想了。
这是数据包离开伦敦后的样子(减去标识IP地址的前几个字节)
0x0040: 0b7c aecc 1774 b770 ad92 0000 00b7 6563 .|...t.p......ec
0x0050: 6468 2d73 6861 322d 6e69 7374 7032 3536 dh-sha2-nistp256
0x0060: 2c65 6364 682d 7368 6132 2d6e 6973 7470 ,ecdh-sha2-nistp
0x0070: 3338 342c 6563 6468 2d73 6861 322d 6e69 384,ecdh-sha2-ni
0x0080: 7374 7035 3231 2c64 6966 6669 652d 6865 stp521,diffie-he
0x0090: 6c6c 6d61 6e2d 6772 6f75 702d 6578 6368 llman-group-exch
0x00a0: 616e 6765 2d73 6861 3235 362c 6469 6666 ange-sha256,diff
0x00b0: 6965 2d68 656c 6c6d 616e 2d67 726f 7570 ie-hellman-group
0x00c0: 2d65 7863 6861 6e67 652d 7368 6131 2c64 -exchange-sha1,d
0x00d0: 6966 6669 652d 6865 6c6c 6d61 6e2d 6772 iffie-hellman-gr
0x00e0: 6f75 7031 342d 7368 6131 2c64 6966 6669 oup14-sha1,diffi
0x00f0: 652d 6865 6c6c 6d61 6e2d 6772 6f75 7031 e-hellman-group1
0x0100: 2d73 6861 3100 0000 2373 7368 2d72 7361 -sha1...#SSH-rsa
0x0110: 2c73 7368 2d64 7373 2c65 6364 7361 2d73 ,SSH-dss,ecdsa-s
0x0120: 6861 322d 6e69 7374 7032 3536 0000 009d ha2-nistp256....
0x0130: 6165 7331 3238 2d63 7472 2c61 6573 3139 aes128-ctr,aes19
0x0140: 322d 6374 722c 6165 7332 3536 2d63 7472 2-ctr,aes256-ctr
0x0150: 2c61 7263 666f 7572 3235 362c 6172 6366 ,arcfour256,arcf
0x0160: 6f75 7231 3238 2c61 6573 3132 382d 6362 our128,aes128-cb
0x0170: 632c 3364 6573 2d63 6263 2c62 6c6f 7766 c,3des-cbc,blowf
0x0180: 6973 682d 6362 632c 6361 7374 3132 382d ish-cbc,cast128-
0x0190: 6362 632c 6165 7331 3932 2d63 6263 2c61 cbc,aes192-cbc,a
0x01a0: 6573 3235 362d 6362 632c 6172 6366 6f75 es256-cbc,arcfou
0x01b0: 722c 7269 6a6e 6461 656c 2d63 6263 406c r,rijndael-cbc@l
0x01c0: 7973 6174 6f72 2e6c 6975 2e73 6500 0000 ysator.liu.se...
0x01d0: 9d61 6573 3132 382d 6374 722c 6165 7331 .aes128-ctr,aes1
0x01e0: 3932 2d63 7472 2c61 6573 3235 362d 6374 92-ctr,aes256-ct
0x01f0: 722c 6172 6366 6f75 7232 3536 2c61 7263 r,arcfour256,arc
0x0200: 666f 7572 3132 382c 6165 7331 3238 2d63 four128,aes128-c
0x0210: 6263 2c33 6465 732d 6362 632c 626c 6f77 bc,3des-cbc,blow
0x0220: 6669 7368 2d63 6263 2c63 6173 7431 3238 fish-cbc,cast128
0x0230: 2d63 6263 2c61 6573 3139 322d 6362 632c -cbc,aes192-cbc,
0x0240: 6165 7332 3536 2d63 6263 2c61 7263 666f aes256-cbc,arcfo
0x0250: 7572 2c72 696a 6e64 6165 6c2d 6362 6340 ur,rijndael-cbc@
0x0260: 6c79 7361 746f 722e 6c69 752e 7365 0000 lysator.liu.se..
0x0270: 00a7 686d 6163 2d6d 6435 2c68 6d61 632d ..hmac-md5,hmac-
0x0280: 7368 6131 2c75 6d61 632d 3634 406f 7065 sha1,umac-64@ope
0x0290: 6e73 7368 2e63 6f6d 2c68 6d61 632d 7368 nSSH.com,hmac-sh
0x02a0: 6132 2d32 3536 2c68 6d61 632d 7368 6132 a2-256,hmac-sha2
0x02b0: 2d32 3536 2d39 362c 686d 6163 2d73 6861 -256-96,hmac-sha
0x02c0: 322d 3531 322c 686d 6163 2d73 6861 322d 2-512,hmac-sha2-
0x02d0: 3531 322d 3936 2c68 6d61 632d 7269 7065 512-96,hmac-ripe
0x02e0: 6d64 3136 302c 686d 6163 2d72 6970 656d md160,hmac-ripem
0x02f0: 6431 3630 406f 7065 6e73 7368 2e63 6f6d d160@openSSH.com
0x0300: 2c68 6d61 632d 7368 6131 2d39 362c 686d ,hmac-sha1-96,hm
0x0310: 6163 2d6d 6435 2d39 3600 0000 a768 6d61 ac-md5-96....hma
0x0320: 632d 6d64 352c 686d 6163 2d73 6861 312c c-md5,hmac-sha1,
0x0330: 756d 6163 2d36 3440 6f70 656e 7373 682e umac-64@openSSH.
0x0340: 636f 6d2c 686d 6163 2d73 6861 322d 3235 com,hmac-sha2-25
0x0350: 362c 686d 6163 2d73 6861 322d 3235 362d 6,hmac-sha2-256-
0x0360: 3936 2c68 6d61 632d 7368 6132 2d35 3132 96,hmac-sha2-512
0x0370: 2c68 6d61 632d 7368 6132 2d35 3132 2d39 ,hmac-sha2-512-9
0x0380: 362c 686d 6163 2d72 6970 656d 6431 3630 6,hmac-ripemd160
0x0390: 2c68 6d61 632d 7269 7065 6d64 3136 3040 ,hmac-ripemd160@
0x03a0: 6f70 656e 7373 682e 636f 6d2c 686d 6163 openSSH.com,hmac
0x03b0: 2d73 6861 312d 3936 2c68 6d61 632d 6d64 -sha1-96,hmac-md
0x03c0: 352d 3936 0000 0015 6e6f 6e65 2c7a 6c69 5-96....none,zli
0x03d0: 6240 6f70 656e 7373 682e 636f 6d00 0000 b@openSSH.com...
0x03e0: 156e 6f6e 652c 7a6c 6962 406f 7065 6e73 .none,zlib@opens
0x03f0: 7368 2e63 6f6d 0000 0000 0000 0000 0000 sh.com..........
0x0400: 0000 0000 0000 0000 0000 0000 ............
这就是当它到达蒙特利尔时的样子
0x0040: 0b7c aecc 1774 b770 ad92 0000 00b7 6563 .|...t.p......ec
0x0050: 6468 2d73 6861 322d 6e69 7374 7032 3536 dh-sha2-nistp256
0x0060: 2c65 6364 682d 7368 6132 2d6e 6973 7470 ,ecdh-sha2-nistp
0x0070: 3338 342c 6563 6468 2d73 6861 322d 6e69 384,ecdh-sha2-ni
0x0080: 7374 7035 3231 2c64 6966 6669 652d 6865 stp521,diffie-he
0x0090: 6c6c 6d61 6e2d 6772 6f75 702d 6578 6368 llman-group-exch
0x00a0: 616e 6765 2d73 6861 3235 362c 6469 6666 ange-sha256,diff
0x00b0: 6965 2d68 656c 6c6d 616e 2d67 726f 7570 ie-hellman-group
0x00c0: 2d65 7863 6861 6e67 652d 7368 6131 2c64 -exchange-sha1,d
0x00d0: 6966 6669 652d 6865 6c6c 6d61 6e2d 6772 iffie-hellman-gr
0x00e0: 6f75 7031 342d 7368 6131 2c64 6966 6669 oup14-sha1,diffi
0x00f0: 652d 6865 6c6c 6d61 6e2d 6772 6f75 7031 e-hellman-group1
0x0100: 2d73 6861 3100 0000 2373 7368 2d72 7361 -sha1...#SSH-rsa
0x0110: 2c73 7368 2d64 7373 2c65 6364 7361 2d73 ,SSH-dss,ecdsa-s
0x0120: 6861 322d 6e69 7374 7032 3536 0000 009d ha2-nistp256....
0x0130: 6165 7331 3238 2d63 7472 2c61 6573 3139 aes128-ctr,aes19
0x0140: 322d 6374 722c 6165 7332 3536 2d63 7472 2-ctr,aes256-ctr
0x0150: 2c61 7263 666f 7572 3235 362c 6172 6366 ,arcfour256,arcf
0x0160: 6f75 7231 3238 2c61 6573 3132 382d 6362 our128,aes128-cb
0x0170: 632c 3364 6573 2d63 6263 2c62 6c6f 7766 c,3des-cbc,blowf
0x0180: 6973 682d 6362 632c 6361 7374 3132 382d ish-cbc,cast128-
0x0190: 6362 632c 6165 7331 3932 2d63 6263 2c61 cbc,aes192-cbc,a
0x01a0: 6573 3235 362d 6362 632c 6172 6366 6f75 es256-cbc,arcfou
0x01b0: 722c 7269 6a6e 6461 656c 2d63 6263 406c r,rijndael-cbc@l
0x01c0: 7973 6174 6f72 2e6c 6975 2e73 6500 0000 ysator.liu.se...
0x01d0: 9d61 6573 3132 382d 6374 722c 6165 7331 .aes128-ctr,aes1
0x01e0: 3932 2d63 7472 2c61 6573 3235 362d 6374 92-ctr,aes256-ct
0x01f0: 722c 6172 6366 6f75 7232 3536 2c61 7263 r,arcfour256,arc
0x0200: 666f 7572 3132 382c 6165 7331 3238 2d63 four128,aes128-c
0x0210: 6263 2c33 6465 732d 6362 632c 626c 6f77 bc,3des-cbc,blow
0x0220: 6669 7368 2d63 6263 2c63 6173 7431 3238 fish-cbc,cast128
0x0230: 2d63 6263 2c61 6573 3139 322d 6362 632c -cbc,aes192-cbc,
0x0240: 6165 7332 3536 2d63 6263 2c61 7263 666f aes256-cbc,arcfo
0x0250: 7572 2c72 696a 6e64 6165 6c2d 6362 7340 ur,rijndael-cbs@
0x0260: 6c79 7361 746f 722e 6c69 752e 7365 1000 lysator.liu.se..
0x0270: 00a7 686d 6163 2d6d 6435 2c68 6d61 732d ..hmac-md5,hmas-
0x0280: 7368 6131 2c75 6d61 632d 3634 406f 7065 sha1,umac-64@ope
0x0290: 6e73 7368 2e63 6f6d 2c68 6d61 632d 7368 nSSH.com,hmac-sh
0x02a0: 6132 2d32 3536 2c68 6d61 632d 7368 7132 a2-256,hmac-shq2
0x02b0: 2d32 3536 2d39 362c 686d 6163 2d73 7861 -256-96,hmac-sxa
0x02c0: 322d 3531 322c 686d 6163 2d73 6861 322d 2-512,hmac-sha2-
0x02d0: 3531 322d 3936 2c68 6d61 632d 7269 7065 512-96,hmac-ripe
0x02e0: 6d64 3136 302c 686d 6163 2d72 6970 756d md160,hmac-ripum
0x02f0: 6431 3630 406f 7065 6e73 7368 2e63 7f6d d160@openSSH.c.m
0x0300: 2c68 6d61 632d 7368 6131 2d39 362c 786d ,hmac-sha1-96,xm
0x0310: 6163 2d6d 6435 2d39 3600 0000 a768 7d61 ac-md5-96....h}a
0x0320: 632d 6d64 352c 686d 6163 2d73 6861 312c c-md5,hmac-sha1,
0x0330: 756d 6163 2d36 3440 6f70 656e 7373 782e umac-64@openssx.
0x0340: 636f 6d2c 686d 6163 2d73 6861 322d 3235 com,hmac-sha2-25
0x0350: 362c 686d 6163 2d73 6861 322d 3235 362d 6,hmac-sha2-256-
0x0360: 3936 2c68 6d61 632d 7368 6132 2d35 3132 96,hmac-sha2-512
0x0370: 2c68 6d61 632d 7368 6132 2d35 3132 3d39 ,hmac-sha2-512=9
0x0380: 362c 686d 6163 2d72 6970 656d 6431 3630 6,hmac-ripemd160
0x0390: 2c68 6d61 632d 7269 7065 6d64 3136 3040 ,hmac-ripemd160@
0x03a0: 6f70 656e 7373 682e 636f 6d2c 686d 7163 openSSH.com,hmqc
0x03b0: 2d73 6861 312d 3936 2c68 6d61 632d 7d64 -sha1-96,hmac-}d
0x03c0: 352d 3936 0000 0015 6e6f 6e65 2c7a 7c69 5-96....none,z|i
0x03d0: 6240 6f70 656e 7373 682e 636f 6d00 0000 b@openSSH.com...
0x03e0: 156e 6f6e 652c 7a6c 6962 406f 7065 6e73 .none,zlib@opens
0x03f0: 7368 2e63 6f6d 0000 0000 0000 0000 0000 sh.com..........
0x0400: 0000 0000 0000 0000 0000 0000 ............
你有没有注意到?如果没有,那没关系。您可以在文本编辑器中复制到两个窗口中,然后在它们之间快速切换以查看符号更改。
好吧。这不是数据包丢失,而是数据包损坏!很小,非常可预测的损坏。有趣的观察:
- 数据包的初始部分(<576字节)是完整的。
- 16个字节中的每15个字节都会损坏。
- 损坏是可以预见的。全部
h
成了x
,所有c
成了s
。
您可能已经查阅了ASCII表并得出结论,该值卡住了一位
1
。变成1
一个字节的第四位会破坏左边的前一个字母到右边的值。
我们的视野中明显的罪魁祸首(NIC接受服务器)令人怀疑,因为故障有一种模式(多台伦敦机器→多台蒙特利尔数据中心和机器)。原因必须在路线上并且更靠近伦敦。
情况开始变得有意义。我还注意到在详细的tcpdump模式下有一些提示(
tcp cksum bad
),这是我之前从未注意到的。当蒙特利尔服务器意识到它已损坏并且没有将数据包转发到用户空间中的SSH守护程序时,它丢弃了一个内核级数据包。然后,伦敦再次发送了该小包,再次将其损坏,蒙特利尔默默地将其丢弃。就SSH和SSHd而言,连接被卡住了。从tcpdump的角度来看,没有损失,Montreal服务器只是忽略了数据。
我们向伦敦数据中心运营部门报告了我们的发现,几分钟后,他们就大大改变了出站路由。第一跳和大多数后续跳均不同。冻结问题消失了。
星期五晚上的修复很不错,因为在周末您可以放松身心,而不必考虑问题和支持:)
沃利在哪里?
很高兴我们不再受此问题困扰,而且我们的系统正在追赶,我决定找到造成此数据包损坏的设备。
更新伦敦路线以使交通不偏离旧路线,这意味着我无法轻松重现该问题。我在蒙特利尔找到了一个朋友,那里有一部适合的FreeBSD机器,该机器可以从伦敦通过旧路线获得。
我想确保即使不使用SSH,也可以预期损坏。我通过一些管道轻松管理了此任务。
在蒙特利尔:
nc -l -p 4000 > /dev/null
然后在伦敦:
cat /dev/zero | nc mtl 4000
考虑到重试周期中的随机性和调整因素,我收到了一些软件包,这些软件包消除了对先前结论的任何怀疑。这是其中一个软件包的一部分:
我们刚刚发送了零数据包
0x0210 .....
0x0220 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0230 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0240 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0250 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0260 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0270 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0280 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0290 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02a0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02b0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02c0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02d0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02e0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x02f0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0300 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0310 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0320 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0330 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0340 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0350 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0360 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0370 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0380 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x0390 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03a0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03b0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03c0 0000 0000 0000 0000 0000 0000 0000 1000 ................
0x03d0 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x03e0 .....
重现该错误,我需要找到发生损坏的17个跃点之一。我不能只打电话给所有集群的提供者并要求他们检查他们的系统。
我决定按顺序ping通每个路由器,这可能会有所帮助。编写足够大以超过576字节安全限制的特殊ICMP数据包,并用零填充它们。然后使用这些数据包从伦敦ping蒙特利尔服务器。
包返回原样。
我尝试过速度,内容,大小的所有组合-都无济于事。我在返回的ICMP ping数据包中未发现任何损坏。
在netcat管道中,我已将TCP替换为UDP。同样,没有损坏。
它需要TCP来再现损坏,并且TCP需要两个通信端点。我徒劳地尝试找出所有路由器是否都具有可直接与之通信的开放TCP端口。
似乎不可能从外部识别出错误的跃点。还是有可能?
镜子,墙上的镜子
要确定是否发生损坏,必须使用以下情形之一:
- 通过与之通信的TCP节点检查目的地的数据包。
- 不在用户空间中,在校验和验证期间发生错误时不会传送数据包的用户空间中,而是使用root和tcpdump检查接收到的数据包是否损坏。
- 使用充当回显服务器并向后镜像接收到的数据的TCP节点,检查发送节点上的数据包。
突然发现第二个测量点可供我们使用。尚不直接可用,但仍然可用:在解决问题的第一种方法中,我们注意到SSH客户端通过破坏性跃点与SSH服务器通信时挂起。这是一个很好的无源信号,可以代替有源“回波”信号使用。
因此,Internet上许多开放的SSH服务器可以帮助我们。
我们不需要这些服务器上的往来帐户,我们只需要启动SSH连接,看看密码交换阶段是否会成功(可以进行合理的重试次数,以考虑意外损坏)。
计划是这样的:
- 在“随机IP”模式下使用出色的nmap工具可以编译一系列地理位置分散的开放式SSH服务器。
- :
- , → .
- N- → «».
- telltale N- → «».
- «» «».
我是这样认为的:在跟踪所有“不良”服务器时,将使用几个相同的跃点。我们将能够识别可疑的跃点,并识别出在“良好”服务器痕迹中使用的跃点。希望能保留一两个。
在花了一个小时手动对服务器进行分类之后,我停止浏览数据。我有16个“坏”服务器和25个“好”服务器。
第一步是列出出现在“不良”服务器的所有跟踪中的跃点列表。清除列表后,我意识到我什至不需要去“好”列表来消除误报。坏人只有一跳。
但是,之前有两个提供者:伦敦→N跳上游1→Y跳上游2。
这是上游2中的第一个Y跃点,就在上游1和上游2之间的边界上。它损坏了随机的TCP数据包,从而导致大量重传,并且根据协议数据交换的具体情况,冻结或减少了传输量。
我们与伦敦数据中心运营部门一起跟踪了该跃点的IP地址。我希望通过它们与上游1的直接链接,可以强制进行更正。
通过上游1,我收到确认信息,表明我指示的跃点(上游2中的第一个跃点)具有内部“控制模块故障”,这会影响BGP和两个内部网络之间的路由。他们重新路由了故障设备,并关闭了设备,等待更换。
摇滚音乐过滤器
我帮助流音频应用程序的用户设置了LAN体验。用户仅播放古典音乐,而不播放摇滚音乐。说真的经典流无缝地播放,并且当尝试流摇滚音乐时,连接在几分钟后断开。
该应用程序接收音频块,使用无损压缩编解码器对其进行压缩,然后将每个块以单独的UDP数据包发送到端点。该应用程序尝试使用IPv6,因为它比LAN环境更可靠,尽管它在必要时可以在IPv4上运行。
在无休止地寻找问题的原因之后,我终于弄清楚了问题所在。用户已以某种方式在网络接口上将MTU设置为1200字节。当MTU低于1280字节时,IPv6不会在IP级别自动分割数据包,因此根本无法发送更大的数据包。流媒体应用程序将尝试发送大于1200字节的音频数据包,接收错误并断开连接。
为什么只有摇滚音乐会发生这种情况?这很简单。无损编解码器使用可变比特率,并且古典音乐比摇滚音乐具有更好的压缩效果。在流式传输经典歌曲时,音频始终被压缩为小于1200字节的数据包,摇滚音乐数据包随机超过此阈值。
用户不知道为什么减少了他的MTU,他不需要它,所以我们增加了价值,并且一切正常。
自我消失的互联网破坏
当我1999年进入大学时,我住在一个破旧不堪的学生宿舍,因为我买不起更好的东西。但是,至少在旅馆中有一个相当不错的互联网,在我国尚未普及。由于禁止更改建筑物,因此根据临时方案将网络电缆(仍为同轴电缆)离婚了。它们被藏在走廊的假天花板后面,并穿过门口进入房间,在那里它们只是躺在地板上。通讯中断可能会导致整个楼层都没有网络。自从我在计算机科学学院学习以来,尽管我根本没有网络方面的经验,但我很快不由自主地变成了固定地板上经常打扰的人。
有时,中断是由提供商提供的,有时问题是与我们的代理有关的,但更多的情况是,有人只是简单地断开了某些电缆,而没有在其中插入终结器。
一天晚上,互联网瘫痪了,但只有几分钟。然后他又出现了,所以我没有考虑太多。但是第二天又重复了短暂的打扰,第三天也是如此。通常情况下,发生时间约为20小时,确切时间浮动,有时甚至根本没有。但是每次网络中断时,我的现场电话都会响起,这些反复的干扰使人们越来越烦恼。
由于每次中断仅持续了几分钟,因此我无法在网络重新出现之前查明特定位置。我试图越过地板,敲开所有的门,问是否有人拉出电缆或用电缆做过什么,但是这个想法没有帮助。最终,我决定用我值得信赖的万用表等待每天的中断。在一周之内,我从犯罪嫌疑人那里逐出了一个房间。最后,在其中一根房间电缆中,我注意到下一次中断时电阻激增。
我敲了敲门,但他们没有打开。城堡被锁了。但是,如果房间里没有人可以使用计算机或电缆做某事,那么为什么会中断连接?为什么恢复呢?第二天,一切再次发生,他们没有再开门。我决定完全关闭此房间,以使Internet可以在其余楼层正常工作。
第二天早上,那个房间的房客告诉我他们的互联网无法正常工作。我去找他们,测量了所有电缆的电阻,检查了所有连接和端接器。所有电缆的电阻均为零欧姆,一切都处于完美状态。我问那个家伙他昨晚在做什么?他回答说,我在考试前读过教科书,与计算机无关。我第二次和第三次都检查了所有内容,但没有发现任何问题。我差点放弃,然后我发现:电缆固定在床下了。当然,电缆的铜芯此时恰好断裂了,但是用护套将其牢牢地固定住,因此在正常情况下,即使您坐在床上也可以保持接触。但是当我开始摆动它时,每次按下该接触都会消失几秒钟。
您自己可以猜出每天晚上在床上,在锁着门后的几分钟内发生了什么,而没有敲门的答案。
梅尔的故事
真正的程序员用Fortran编写
在无酒精啤酒,计算器和“用户友好”应用程序的衰落时代,现在可能就是这种情况,但是在“好时光”时期,“软件”一词听起来很有趣,而Real Computers由磁鼓和无线电管组成,Real Programmers在机器代码。不是在FORTRAN。不在RATFOR上。甚至没有汇编语言。在机器代码中。实数,未经修饰,难以理解的十六进制数。就这样几代程序员已经长大成人,却不知道这个光荣的过去,我相信我应该尝试弥合一代人的鸿沟,并谈论真正的程序员如何编写代码。我叫他梅尔,因为那是他的名字。
当我在Royal McBee Computer Corp.工作时结识了Mel,这是一家打字机制造商现已倒闭的子公司。该公司正在制造LGP-30(这是一种小型且便宜的(按今天的标准)鼓计算机),并且刚刚开始生产RPC-4000(同样在鼓存储器上),得到了很大的改进,更大和更快。磁芯太昂贵了,它们经不起竞争(这就是为什么您没有听说过该公司或其计算机的原因)。我受雇为这个新奇迹编写FORTRAN编译器,而梅尔是其功能的指导。梅尔不赞成编译器。他问:“程序不能重写自己的代码有什么好处?”梅尔用十六进制编写了该公司最受欢迎的程序。她曾在LGP-30上工作,并在计算机展览会上与潜在买家打了二十一点。它一直具有戏剧性的效果。每个贸易展览会上都有一个LGP-30展位,IBM供应商聚集在一起并互相交谈。它有助于销售计算机吗?我们从未讨论过这个问题。
梅尔的工作是为RPC-4000重写二十一点程序。 (移植?是什么?)新计算机具有一个一对一的寻址方案:除了操作码和所需操作数的地址外,每条机器指令还具有第二个地址,该地址显示了下一条指令在旋转的磁鼓上的写入位置。 ...也就是说,每条指令执行完之后
GO TO
!将其塞入Pascal烟斗中并抽烟。
梅尔(Mel)喜欢RPC-4000,因为他可以优化自己的代码:将指令放在卷轴上,这样一来,一旦完成,第二个就在“读头”下面,并准备立即执行。为此,编写了一个优化汇编程序的程序,但Mel拒绝使用它。他解释说:“您永远都不知道将数据放在何处,因此必须使用单独的常量。”我很晚才理解这句话的实质。由于梅尔知道所有操作码的数值并在感光鼓存储器中分配了自己的地址,因此他编写的每条指令都可以视为数字常数。例如,他可以选择一个较早的“加”指令,如果它具有合适的数值,则乘以该指令。很少有人可以更改其代码。我将Mel的手动优化程序与优化汇编程序处理过的相同代码进行了比较,并且Mel的代码始终运行得更快。事实是尚未提出自上而下的建筑结构方法,Mal也不会使用它。首先,他编写了编程循环的内部部分,以便它们最先在卷轴上获得最佳地址。而且优化的汇编程序无法做到这一点。即使笨拙的Flexowriter需要字符输出之间的延迟,Mel也从未编写过延时循环。梅尔只是将说明放在卷轴上,这样当必须阅读下一条说明时,它就会通过自上而下的体系结构方法还没有被发明出来,而梅尔也不会使用它。首先,他编写了编程循环的内部部分,以便它们最先在卷轴上获得最佳地址。而且优化的汇编程序无法做到这一点。即使笨拙的Flexowriter需要字符输出之间的延迟,Mel也从未编写过延时循环。梅尔只是将说明放在卷盘上,这样当必须阅读下一条说明时,它就会通过自上而下的架构方法还没有被发明出来,而梅尔也不会使用它。首先,他编写了编程循环的内部部分,以便它们最先在卷轴上获得最佳地址。而且优化的汇编程序无法做到这一点。即使笨拙的Flexowriter需要字符输出之间的延迟,Mel也从未编写过延时循环。梅尔只是将说明放在卷盘上,这样当必须阅读下一条说明时,它就会通过即使笨拙的Flexowriter需要字符输出之间的延迟。梅尔只是将说明放在卷盘上,这样当必须阅读下一条说明时,它就会通过即使笨拙的Flexowriter需要字符输出之间的延迟。梅尔只是将说明放在卷盘上,以便在阅读下一条说明时可以通过越过已读取的磁头,鼓将不得不再旋转一圈才能找到它。梅尔(Mel)为这个程序找到了一个独特的名词。单词“最优”(optimum)具有绝对含义,也具有“唯一”的含义,因此在口语中,它们通常是相对的:“不是很理想”或“不是最优”或“不是很理想”。梅尔称滞后时间最长的鼓上的位置为“最悲观”(“最悲观” -人体可以忍受的最恶劣的环境条件)。
在完成了二十一点程序并运行它之后(“骄傲地初始化了初始化程序,”他自豪地说),梅尔收到了销售部门的要求进行更改。一个优雅的(优化的)随机数生成器负责洗牌,并在程序中从甲板进行交易。一些销售人员认为这太诚实了,因为有时买家会迷失方向。他们要求梅尔更改程序,以便控制台上的触摸开关可以更改玩家的赔率,并让买方获胜。梅尔拒绝了。他认为这是不诚实的-是这样-并且侵犯了他的程序员的道德-是-所以他拒绝参加。销售部门负责人,Big Boss以及在Boss坚持下的其他程序员说服了Mel。最终,梅尔放弃了并编写了代码但是作弊检查是否反过来说:打开开关时,程序作弊并总是赢。梅尔对他的决定感到高兴。他声称自己的潜意识显示出无法控制的道德,并坚决拒绝更正该程序。当梅尔离开公司赚取更高的收入时,大老板让我看一下代码,并告诉我是否可以找到验证器并更改其工作方式。我勉强同意。我可以找到验证模块并更改其工作方式吗?我勉强同意。我可以找到验证模块并更改其工作方式吗?我勉强同意。
处理梅尔的代码是一次真正的冒险。在我看来,编程通常是一种艺术形式,其真正价值只有那些了解这种神秘艺术的人才能欣赏。它包含真正的珠宝和出色的举动,由于过程的本质,有时甚至永远无法被人看到和欣赏。您只需阅读其代码(甚至十六进制),就可以了解有关一个人的很多知识。我认为梅尔是一个无法识别的天才。也许最有力的冲击是我发现的无辜周期,其中没有欺诈性的核实。没有验证。没有。
根据常识,这应该是一个闭环,程序在其中永远循环不断。但是,软件控制已成功通过它,并在另一侧安全退出。我花了两个星期才弄清楚。 RPC-4000配备了现代化的设备-索引寄存器。它允许编写程序循环,并在其中使用了索引指令。每次循环时,都会将来自寄存器的数字添加到指令地址,以便它引用该系列中的下一个位置。剩下的就是每次通过都增加索引寄存器。梅尔没有利用这一点。取而代之的是,他将指令拉入机器寄存器,在其地址中添加了一条,然后将其保存回去。然后,它直接从寄存器执行修改后的指令。编写该循环时要考虑到额外的执行时间:指令完成后,下一个指令将出现在感光鼓的读数头下方。但是循环中没有流氓检查。节省的线索是索引寄存器中的某个位已打开-它位于地址和操作代码之间的命令代码中。但是,梅尔不使用索引寄存器,而是将其保留为零。
当我的顿悟来临时,我几乎失明了。他正在处理的数据接近高级内存(指令可以引用的最大地址)附近的梅尔,以便在处理完最后一个位置后,增加指令地址将导致溢出。在传输期间,将一个代码添加到了操作代码中,将其更改为集合中的以下代码:跳转指令。当然,下一条指令位于地址零,程序愉快地到达了那里。我没有和梅尔谈过,也不知道他是否因为面对自那以后充斥着编程的大量变革而放弃了。我更想我没有放弃。我印象深刻,以至于我停止寻找作弊支票,并告诉大老板我找不到。他并不感到惊讶。我离开公司时如果打开了正确的开关,二十一点程序仍在作弊,我认为是正确的。我不喜欢破解Real Programmer的代码。
USB异常问题
刚从大学毕业后,我加入了一家公司,并在消费类设备上工作了五个月,然后才向公众展示。该设备正在运行Linux。当我习惯了在内核空间中进行纵容的想法时,我被迫参加一次会议以优先考虑错误。许多错误。数百个错误。他们每个人都说:“这是不可能的,这是怎么发生的?”
他们大喊:“内存损坏!”我以为“ Hospadi,请修复您的错误”。看着垃圾场,我们看到了……是什么?该程序通过使用标准库中的函数将两个字符串连接在一起来执行禁止指令。嗯,很奇怪...下一个日志:无法从根本没有分配页面文件空间的设备上的页面文件中获取页面(我想我知道为什么我们无法获取页面!)。
我曾经写过一个简短的程序。它将80%的系统内存分配给单个数组,并向其写入连续的整数。然后,我等待按下Enter键并检查数组的内容是否已更改。现在,我下载了此程序,等待了30秒钟,然后运行了检查。没问题。我尝试了几次-哈,我知道没有记忆障碍!我拔出了调试电缆(USB),经过10秒钟后,我迅速插入并拔出,然后重新插入。 am! 90个错误。
你的
好的,我必须修补USB端口。那问题和他有关吗? USB驱动程序似乎没有实现随机抛出位错误的魔术位仙子算法。可能是硬件有问题?不,不是他,但那并没有阻止我们对USB端口进行各种all测。他们邀请了很久以前切换到另一种产品的工程师,现在他们为这个问题感到困惑。我不记得我们花了多少时间证明自己的硬件是完整,完整,糟糕的。接地良好,电压稳定,时钟运行准确,并且DDR线非常完美,当您看到它时会哭得很开心。
经过工程师测试的设备变得越来越不稳定。我假设计算机可以将数据加载到内存中,获取位错误,然后将其转回到闪存中,甚至在错误的位置(页面表也经常损坏,因此可以假设这也发生在文件跟踪结构中)内容可能写到了错误的位置,文件系统的结构也可能损坏,等等。)随着时间的流逝,设备的性能下降到足以使它们无法可靠启动的程度。最后,一位工程师崩溃了,并覆盖了他笔记本电脑上的图像。这个图像是比较古老的。
-老兄关于软件。
- 什么?!?!?!我向你保证,我们没有写仙子!
否:三个月前他上传了一个程序集,问题消失了。那一刻,我觉得有责任让一群人参与到一个漫长而毫无意义的冒险中,所以我呆了一夜,在过去的几个月中对所有补丁进行了二进制搜索(花了更多的时间研究整个操作系统的完整组件) ...)。
那么那个魔术补丁是什么?有人在内核中添加了我们分析过的芯片的驱动程序。该芯片不在设备中。
哈!我们找到了一个女巫!烧掉它吧!
许多人宣布问题已解决。他们很高兴在下一个发行版中可以回滚补丁并继续前进。我们极其挑剔地将其回滚,整理图像,对其进行测试,一切都很好。我们没想到几天后会在原子核中出现相同的缺陷。
等待。如果芯片不在板上,驱动程序如何阻止我们?我运行了lsmod,未加载驱动程序...“无论如何,有什么区别,删除模块文件并重新加载。 Nifiga,问题仍然存在。这不正常...”
现在我一个人,看着魔鬼还在继续。开始仔细分析补丁。这是芯片制造商提供的一个很好的10K C行文件。用“混乱”一词来形容它实在是太屈从了(公平地说,几周后,他们给我们派了一个更周到的司机)。深入研究之后,我决定在驱动程序中未实现“玩转玩法”。那怎么办?五行代码中的48个字节。引导文件中的一个小结构,指示要查找芯片的总线地址。我删除了大多数驱动程序,但其中保留了其他结构。问题仍然存在。
所以男孩和女孩,我们有一个对齐问题!这个48字节的结构以某种方式在内存中移动了一些东西,并导致错误。我发现,当您在文件中放入大于32个字节且小于64个字节的内容时,就会发生此问题。这种知识并没有多大帮助,但至少创造了一种进步感。
内核编译产生了一个整洁的System.map文件。它列出了所有编译到内核中的变量在内核的虚拟地址空间中的位置。我发现我的小结构在“ .data”部分的中间。这部分充满了初始化变量,因此,当内核二进制文件解压缩到内存中时,它将从编译的映像中写入所有这些变量。使用System.map作为参考,我实现了一个相当愚蠢的二进制搜索。在大多数情况下,我搜索了不同C文件的链接器。我找到了一个要比较的变量;找到了包含它的内核文件;将我的魔术结构放在我旁边的一个随机文件中,然后开始查看问题是否再次出现。
搜索继续到最后几个.data元素,然后空手返回。内存中没有带有初始化变量的必需数据。当我滚动浏览System.map文件时,我发现我没有注意整个.bss部分,其中包含未初始化的变量。从过去的错误中学到的东西,我首先检查了起点和终点。当然,在节开头的未初始化变量会导致错误,而在节末的变量不会导致错误。找到罪魁祸首只是时间问题。其运动引起问题的变量是...
函数指针?!
函数指针对齐到底如何破坏我们的系统?在ARM体系结构中,访问时如果不对齐就无法读取字,也就是说,每个32位变量必须以4的地址倍数存储到内存中。函数指针也不例外,它始终获取最小地址。事实证明,在我们遇到问题的情况下,地址是2 n的倍数,大于或等于64。任何小于此阈值的值-问题就消失了。指针对齐也有顺序。
没有良好的对齐方式。至少在此错误发生之前。
现在,该函数指针不再是“祖父”指针。他指的是一些特别的东西。如果我们不使用RAM,CPU SRAM中会有一个区域可用于执行与负载相关的任务。为了节省空闲时的能量,我们将子例程复制到该区域,设置引用该子例程的特殊指针,然后对其进行调用。子例程在做什么?让我们看一下汇编器。我不是ARM汇编专家,但是评论很雄辩。
// ...
...
// LPDDR
你在做什么?!您迅速从基本的寄存器操作转移到禁用内存控制器。我给写子程序的制造商发送了一封电子邮件,询问他们是否缺少某些东西。
三天后,我收到了一个回答为“哦,是的,必须有一个记忆障碍”的答案。事实证明,由于L2缓存的结构,如果我们不小心将64的倍数写入内存地址,它们将不得不额外支持TLB,在这种情况下,当控制器关闭时,我们仍然可以使用RAM。
考虑到变量比对需要至少为4的多重性,并且最后一个记录不能具有64或更大的多重性,因此在每次编译时,系统完全无法使用数据的十六分之一。
最后,我们交付了带有内存屏障的可靠产品,客户对此表示满意。是的,如果您想知道,我无法用USB电缆注意到它,因为由于USB的使用,我们无法进入低功耗模式。这纯粹是一个USB问题。
无效的错误消息
在1996年9月17日的最后几个小时,即WebTV服务的预定发布的前一天,我们的小组聚集在帕洛阿尔托的运营中心。大量的网络系统管理员和服务软件开发人员在附近闲逛,目睹了正式发布。
当指定的小时数到来时,其中一位网络人员开始在他的WebTV设备上注册。我们知道好的昵称会很快消失,因此在用户开始注册之前进行注册非常重要。另外,很高兴成为第一个注册第一个“真实”服务的人。在此之前,所有帐户均为“一次性”测试帐户。
几个人围成一团,看着他在键盘上打字,因为期待和睡眠不足而感到头晕。布莱斯输入了他的姓名,地址和其他信息,然后开始输入昵称。那是他的电子邮件地址名称。他输入了“爵士”,这意味着他的邮件应该是“ jazz@webtv.net”当他按无线键盘上的Enter键时,我们听到了独特的声音,表明错误消息的出现。大家看着屏幕。
要了解接下来发生的事情,了解有关该服务的一两件事很重要。 WebTV被定位为家庭电视,因此有必要检查粗言秽语,并过滤掉用户名和其他对用户可见的信息。捕获所有内容是不可能的,但过滤出明显的事物也不难。
将自定义名称与正则表达式列表进行比较,这使它们可以与模式进行匹配。例如,“ fu。* Bar”将与所有以“ fu”开头并以“ bar”结尾的名称进行比较。如果您仔细选择模式,则可以捕获和拒绝带有内置诅咒的“ shitake”和“ matsushita”等令人震惊的变体。
使用相同的机制来防止用户选择“禁止”名称,例如“ postmaster”,“ root”,“ admin”和“ help”。我们有一个像这样的文本文件:
admin.*
"admin".
postmaster
postmaster.
poop
.
weenie
.
每个条目由两行组成。第一行是要与之进行比较的正则表达式,第二行是向用户显示的错误消息。系统一次读取两行文件,当用户输入名称时,会将其与所有正则表达式进行比较。显示找到第一个匹配项的错误消息。如果不匹配,则接受自定义名称。
读取文件的代码知道如何跳过注释。但是他不知道如何处理空行。
有人更改了脏话文件,并在“保留”名称之后和脏话之前添加了一个空白行。当代码读取列表时,它将空字符串作为正则表达式,并将其后的单词作为错误消息。空字符串表达式匹配任何内容。
午夜。我们都处于边缘。布莱斯(Bryce)写下该名称,然后系统以一条简单消息响应:
我们开始歇斯底里地大笑。其他人来找我们,了解发生了什么事。我们将其显示在屏幕上。他们开始歇斯底里地大笑。
当时,马克·阿姆斯特朗(Mark Armstrong)(负责质量检查)和布鲁斯·里克(布鲁斯·里克(Bruce Leek),该公司的创始人之一)坐在16台WebTV控制台柜台前。这个被昵称为“ racksville”的机架通过一个视频多路复用器连接到一台大型电视,同时显示所有16个盒子的图像。马克和布鲁斯开始使用带有红外发射器的键盘注册机顶盒。我们在对讲机上给他们打电话:
-进展如何?
-一切都很好。
-太好了注册时您可能已经注意到了一些事情。
-是的?我们没有发现任何奇怪的事情。
- 注意。
- 好的。输入邮政编码...到目前为止,一切都很好。哎呀!
所有16个控制台的图像上都会出现一条友好消息。老板们建议我们可能需要尽快解决此故障。对我们来说,这似乎是个好主意。
我们修复了文件,并讲授了识别和忽略空行的代码。据我所知,WebTV尚未对任何客户说“ f-k”。
Xbox崩溃问题
当时,该团队正在为一款名为Xbox的全新游戏机开发首批游戏之一。当加快最终测试的速度时,质量检查人员从安装批次中启动了三个机顶盒,以在夜间运行自动化测试。如果昨天的游戏版本在早上仍在测试中,则表明它的稳定性。
不幸的是,其中一个控制台在早上崩溃了。崩溃总是很糟糕,但这是一个极其糟糕的情况:视频卡执行的操作使整个系统崩溃。诊断图形卡问题很困难:没有调试器,没有堆栈跟踪,也没有使用进行调试
printf
。您只能阅读代码并进行实验。
这样就开始了Bug搜寻。首席工程师每天都要审查可用的证据,进行假设并排除可能性。每天晚上,质量检查无缘无故地“随机”掉落。 “这是不可能的”,“这是怎么发生的?”,“也许这是编译器中的错误?” -所有最受欢迎的歌曲。
在工程师的车上,游戏完美运行了好几天。但是,这简直无济于事,因为将游戏发送到印刷厂并运送到商店的截止日期临近。
幸运的是,我们很快就找到了一种模式,尽管这是一个相当奇怪的模式。游戏仅在晚上崩溃,并且仅在三个控制台之一上崩溃。我们开始寻找它们之间的差异。与电源线无关。不在控制器中。 DVD烧坏了。将控制台转移到您的桌子上-它不会掉落。放回去-它掉落了。这是关于质量检查使用的特定立场。
现在,排除因素的过程要求排除所有变量。最后,在绝望中,工程师试图交换表附件。
事实证明,不是特定前缀出现了问题。该表上的所有前缀均下降。在半夜。有时为了科学起见,您必须采取奇怪的举动,这就是其中一种情况。工程师坐直地坐在椅子上,上面放满了红牛罐头,而Bug Hunt变成了Bug Watching。工程师发誓,他将观看在该死的桌子上的控制台上运行的自动化测试,直到他亲眼看到失败为止。
夜晚慢慢过去,然后很快过去,终于到了黎明。游戏继续运行。令人鼓舞。太阳开始升起。
然后有趣的事情终于发生了:一缕初升的太阳落在桌子上。一分钟一分钟,光线从桌子上爬到附件,温暖的光芒悄悄地包裹着附件的黑色圆顶。
哪个跌得很快。
第一个Xbox出现问题:如果控制台温度达到一定值,视频卡可能会发生故障。该软件与它无关。报告了硬件问题,发布了游戏,并用啤酒代替了红牛。好吧,说实话,威士忌。一:科学为零。