除虫故事(三)
第三个bug是刚出的,贝壳刚刚从现场回来,提交了bug系统关闭申请。
问题是这样的,我们有一套系统,为客户提供从web访问某台windows的能力,作为管理系统使用。这个系统的后台使用了三四个不同的程序,通过管道通讯。目标设备上有一个组件,要适应2000/2003/2008的32位和64位环境,非常复杂。最近,贝壳将这套系统的目标设备的组件进行了重编译,提供了64位版本。然后测试发现,32位系统不工作了,64位系统正常。
第一反应是什么?一定是组件有问题?贝壳在服务器上,直接使用连接程序去连接,结果是成功的。这个表明组件应当是正常的,或者部分正常。问题就在web页面到连接程序的过程中某处。
负责web界面到连接程序的工程师同事接手了下一步排查,他也是一头雾水。系统看来一切正常,连接程序明明可以工作,为什么从web页面调用就会失败呢?而且只有32位会失败。web页面对CPU字长(而且是目标设备的CPU字长)并不敏感阿,这个听起来不合理。
测试过程中,测试部门的同事偶然的看了一下日志系统,发现了问题。我们的连接程序会写出日志,默认情况下这个日志的属主应当是web.web的,而当时的日志是root.root的,而且权限是644。所以当连接程序被直接调用,当前id是root,就可以连接成功。而连接程序被web调用,当前id是apache,日志写出就会失败,程序就挂了,目标设备会失去反应。
出现这个错误的原因也很直观,在某次调试后,有人删除了原始的日志,并且直接执行了连接程序。但奇怪的是,同样是连接程序挂掉,为什么64位就可以继续执行呢?我们讨论不出为什么,只有基本猜测,64位设备是2008,rdp服务版本比较高,所以相对健壮。
所以,实际的错误是两个。一个是日志权限导致的连接程序不工作。另一个是64位下不正常的连接程序依旧可以工作。
好吧,总结一下这个奇怪的问题中的教训。
1.隔离最小差异。要验证是否是组件升级导致问题,一定要进行旧组件测试,然后再测试新组件。万不可假定旧组件可以正常运行,直接测试新组件,从而将非组件问题带入排查。
2.单元测试隔离。每个部分都要做单元测试,如果测试通过却无法连接,那就是环境问题。再查不出,再检查通讯/调用记录。
3.通讯系统关联错误。当两个程序通过通讯工作,其中一个程序死亡时。另一个程序应当能够检测并且报错退出,而不是出现各种异常反应。
4.日志底线设计。程序一定要写日志,如果日志写不出,就写系统日志,再写不出,设法报全局错误。