首页 > 代码库 > 休斯顿,我们遇到了一个问题

休斯顿,我们遇到了一个问题

最近和前端同学聊得比较多,聊着聊着发现前端回报了一个诡异的错误,服务器端发给客户端的JSON错了,解不开。前端同学bs了一下服务器用的JSON库,居然连编码都会出错。我检查了所用的库,前后端的确用的不是同一个json.lua,于是跑了一次简单的压测。当然,没有发现问题。过了两天,又遇到同一个问题了,这次我留心了一下错误的详细内容:

 

coco/game.lua:86: coco/lib/json.lua:525: coco/lib/json.lua:240: expected colon at char 119 of: [{"res_amount":5,"id":1,"status":2,"res_type":1},{"res_amount":50000,"id":2,"status":0,"res_type":2},{"res_amount2:5,"id":3,"status":2,"res_type":1},{"res_amount":50000,"id":4,"status":0,"res_type":3},{"res_amount":7,"id":5,"status":0,"res_type":1},{"res_amount":50000,"id":6,"status":0,"res_type":5},{"res_amount":8,"id":7,"status":0,"res_type":1}]

可以看到,具体错误:
{"res_amount2:5,"id":3,"status":2,"res_type":1}

本来是引号的地方,变成了2。比较一下两者的二进制表示:

0011 00102
0010 0010"

两者只差一个比特!再找到上一次的错误,是一个,变成了<:

0010 1100,
0011 1100<

看来,我们遇到了传说中的比特反转!相关的资料可以参考这篇文章。

 

一时好奇心起来,就写了个爬虫,爬了最近十天的日志记录(没有权限查数据库Orz),分析了约80万条日志,总共扫出了6例类似的报错。发生的机型以国产机居多,以下是点名时间(啪啪啪):

SM-G3502
Coolpad 8705
Coolpad 8720L
HUAWEI G521-L076
ASUS_T00F
vivo X3t

品牌从三星到华为,再到接地气的coolpad都有。

相信实际上发生的比特反转几率会比这个还要多,因为发生在json字符串中间,或者json数值中间的,都不会被发现。另外,二进制打包是用protobuf做的,pb包损坏的报错其实也不少,只是这个就没法确认是1比特坏了还是多个比特坏了。据参考资料说,4G内存的PC机,每小时3bit错误到每个月3bit错误都有,而移动设备的数量比PC要多得多,所以出现这种情况一点都不奇怪。

 

及后,我分析了一下我们的协议收发过程,当时实现的时候没有加上验证码。如果加上了,可以补上一个包重发机制,遇到错误的包要求服务器重发。或者添加某些校验码,类似服务器内存使用的ECC,可以让只错了1bit的包恢复回来。第一次发现TCP也会不可靠,哈哈

 

休斯顿,我们遇到了一个问题