会员登录 | 会员注册 | 意见建议 | 网站地图

站长资源综合门户

当前位置:首页 > 站长学院 > 建站经验 > 少写一个`var`是如何毁失落我们网站的

少写一个`var`是如何毁失落我们网站的

时间:2012-01-04 16:44:38   作者:   来源:   点击:

恩,这是名副其实的杯具(很抱愧我用这个词,shitstorm)。长话短说,如今MelonCard已经被TechCrunch使用,然而所有事情都可能突然呈现问题。曩昔几天里,我们对MelonCard进行了巨年夜的改进,使用NodeJS长轮询机制以及平滑的KnockoutJS动态jQuery Templates前端。在完成站点无缝升级,在达成"所有功能都是最新"目标的同时,成为外不雅更美、体验更好的产品。为了避免可能产生的不良影响,我们进行了手工测试和单位测试,并为Node连络使用了一整套Vows。完成所有的系统测试,朝着目标全速前进,对吗?事实并没有那么快。

译注:

长轮询(long polling):是Comet的一种实现体例,也是Facebook,Plurk实现动态更新内容的体例,具体原理是发送一个长时间期待的request,当办事器有资料response的时候立即断失落,接着再发送一个新的request。

Vows:Node.js的异步行为开辟框架

我们的系统用的是NodeJS,按照用户输入决定他确当前状态,例如用户输入"我正在期待更新这两条记实",办事器(基于时间戳查抄)会返回"您的记实已经是最新的"或"记实xxx已更新为yyy。"(实际的过程会比这个加倍复杂,我们使用了Redis同享变量和会话,并对Rails、mySQL、Redis和Node之间的接口进行平安查抄)。(这个过程)看上去很是简单,但当事情不如预期的那样时,即便是简单的NodeJS 代码也会成为恶梦。今天恶梦产生了。

措置完今天的日常工作之后,我们遇到了一个正常的新用户注册岑岭(一个小时内有50-100个新用户注册)。突然之间,所有事情都起头呈现问题,没有一个页面可以正常工作。我们的邮箱起头被"你的产品挂失落了"近似的邮件塞满了。我抓起一杯咖啡准备战斗。

我的第一个反应是:NodeJS能够很好地措置负载,这是众所周知的。50或100个用户不成能让系统解体。在取得Ryan Dahl的帮忙之后,我们知道这不是Node自己的问题(后来的成果也验证了这一点)。办事器起头返回异常成果,用户输入"我的记实是a、b和c"然而办事的答复是"你这个蠢货,删失落x、y和z这里的记实是a、b和c。"即便能够确定问题的范围并可以重复毛病,也几近不成能通过Node可怜的毛病措置和调试功能解决。采取的体例就是下面的unix命令(是的,我对production进行查询)

NODE_ENV='production' node/privacy.js | grep "Returned results"

你能够想象对这些成果进行分类是件多么可骇的事。成果是,所有的分段测试和单位测试都正常,我已经束手无策了。最为重要的是,我们的系统再一次执行了年夜量的(平安性)会话查抄。例如,如果用户在(阅读器)不合的标签页之间进行登录和退出时,会有年夜量的"Unauthorized (未授权)"毛病弹出(这让企图体会真正问题的我们加倍胡涂)。当我列犯毛病的时候,看上去像这样:

Trace: at EventEmitter.<anonymous>(/—/node/privacy.js:118:11) at EventEmitter.emit (events.js:81:20)

毛病呈现的那一行(或唯一返回给我的Node)如下:

process.on('uncaughtException', function (err) { console.log(['Caught exception', err]); console.trace(); });

虽然法度还没有解体,但我仍是没有找到线索。在这里最佳实践也没有体例捕获那一行的毛病(手动前端测试,单位测试,毛病措置,等等)。的确,我应当作负载测试,可是即便(测试)达到了竞争条件同样不克不及让我感应平安。

4个小时以后(当我翻到第503页" Temporarily Unavailable",这时我的结合首创人对每一位失望或好奇的用户答复了致歉的邮件),我意识到问题出在办事器将我的请求输入(请求参数)毛病地当作随机用户请求参数。确切的说,办事器的设计只会对你的请求返回你的相关信息,可是对你的请求产生了毛病的理解。比如你说"我喜欢苹果和甜瓜",可是办事奉告你"不要傻了,你喜欢的是芒果。"所以,虽然(从平安的角度来讲)一切都是平安的,可是成果是错的。为什么我的ExpressJS办事器不克不及理解我的请求呢。我继续追踪发现了下面的代码:

app.all('/apps/:user_id/status', function(req, res, next) {

// …

initial = extractVariables(req.body);

});

看上去很糟糕是吧?这是个该死的策略。我不是个JavaScript专家,但请允许我尽我所能为你诠释(或也决心看看这里)。在JavaScript里,你可以声明变量为函数(局部)变量或全局变量(在变量声明/引用的作用域链表上为其增加复杂性,直到最后确定为全局变量)。当我没有使用var来声明一个全局变量initial时,它会遍历作用域链表直到全局范围,最后会成立一个全局变量initial。当下一个请求来到时,它会遍历同样的链表并重写该变量(另外一个请求仍然希望使用这个变量)。每个请求城市重复这一过程。当办事器试图在接下来的措置中答复每个请求时,它会读到不竭被截断的变量,并返回的成果不正常,甚至可以说是荒诞乖张。因此我应当这么修改:

分享到:

网友评论

热门建站经验