在4個(gè)小時(shí)宕機(jī)并令上百個(gè)用戶絕望而歸之后,我找到了問(wèn)題的關(guān)鍵并修復(fù)了產(chǎn)品。風(fēng)雨之后,撥云見(jiàn)日。我們開始對(duì)受到影響的用戶致歉,清點(diǎn)這次事變的損失并繼承工作。但是,缺乏一個(gè)要害字帶來(lái)這樣的喪失還是讓我感到難以釋懷。少寫了一個(gè)var會(huì)讓我成為壞人嗎?
恩,這是貨真價(jià)實(shí)的杯具(很負(fù)疚我用這個(gè)詞,shitstorm)。長(zhǎng)話短說(shuō),現(xiàn)在MelonCard已經(jīng)被TechCrunch使用,然而所有事情都可能突然出現(xiàn)問(wèn)題。從前多少天里,我們對(duì)MelonCard進(jìn)行了宏大的改良,使用NodeJS長(zhǎng)輪詢機(jī)制以及平滑的KnockoutJS動(dòng)態(tài)jQuery Templates前端。在實(shí)現(xiàn)站點(diǎn)無(wú)縫進(jìn)級(jí),在達(dá)成“所有功能都是最新”目標(biāo)的同時(shí),成為外觀更美、休會(huì)更好的產(chǎn)品。為了防止可能發(fā)生的不良影響,我們進(jìn)行了手工測(cè)試和單元測(cè)試,并為Node聯(lián)合使用了一整套Vows。完成所有的系統(tǒng)測(cè)試,朝著目的全速前進(jìn),對(duì)嗎?事實(shí)并沒(méi)有那么快。 處置完今天的日常工作之后,我們碰到了一個(gè)畸形的新用戶注冊(cè)頂峰(一個(gè)小時(shí)內(nèi)有50-100個(gè)新用戶注冊(cè))。忽然之間,所有事情都開端呈現(xiàn)問(wèn)題,不一個(gè)頁(yè)面能夠正常工作。我們的郵箱開始被“你的產(chǎn)品掛掉了”相似的郵件塞滿了。我抓起一杯咖啡籌備戰(zhàn)役。 Vows:Node.js的異步行動(dòng)開發(fā)框架 譯注: 看上去很蹩腳是吧?這是個(gè)該逝世的策略。我不是個(gè)JavaScript專家,但請(qǐng)容許我盡我所能為你說(shuō)明(或者也刻意看看這里)。在JavaScript里,你可以申明變量為函數(shù)(部分)變量或者全局變量(在變量聲明/援用的作用域鏈表上為其增添復(fù)雜性,直到最后肯定為全局變量)。當(dāng)我沒(méi)有使用var來(lái)聲明一個(gè)全局變量initial時(shí),它會(huì)遍歷作用域鏈表直到全局規(guī)模,最后會(huì)創(chuàng)建一個(gè)全局變量initial。當(dāng)下一個(gè)請(qǐng)求來(lái)到時(shí),它會(huì)遍歷同樣的鏈表并重寫該變量(另一個(gè)請(qǐng)求依然盼望使用這個(gè)變量)。每個(gè)請(qǐng)求都會(huì)重復(fù)這一過(guò)程。當(dāng)服務(wù)器試圖在接下來(lái)的處理中回復(fù)每個(gè)請(qǐng)求時(shí),它會(huì)讀到一直被截?cái)嗟淖兞浚⒎祷氐慕Y(jié)果不正常,甚至可以說(shuō)是荒謬。因此我應(yīng)當(dāng)這么修正: NODE_ENV='production' node/privacy.js | grep "Returned results" 這樣會(huì)在我的匿名函數(shù)作用域內(nèi)創(chuàng)立這個(gè)變量,因而接下來(lái)的請(qǐng)求就不會(huì)截?cái)噙@個(gè)值。這是新手才會(huì)犯的錯(cuò)誤,但是在我做的所有調(diào)試或測(cè)試中都完整不會(huì)帶來(lái)競(jìng)爭(zhēng)/并提問(wèn)題。 你能夠設(shè)想對(duì)這些結(jié)果進(jìn)行分類是件如許可怕的事。結(jié)果是,所有的分段測(cè)試和單元測(cè)試都正常,我已經(jīng)一籌莫展了。最為主要的是,我們的系統(tǒng)再一次履行了大量的(安全性)會(huì)話檢查。例如,假如用戶在(閱讀器)不同的標(biāo)簽頁(yè)之間進(jìn)行登錄和退出時(shí),會(huì)有大批的“Unauthorized (未受權(quán))”錯(cuò)誤彈出(這讓打算懂得真正問(wèn)題的我們更加糊涂)。當(dāng)我列犯錯(cuò)誤的時(shí)候,看上去像這樣: 錯(cuò)誤涌現(xiàn)的那一行(或獨(dú)一返回給我的Node)如下: 長(zhǎng)輪詢(long polling):是Comet的一種實(shí)現(xiàn)方法,也是Facebook,Plurk實(shí)現(xiàn)動(dòng)態(tài)更新內(nèi)容的方式,詳細(xì)原理是發(fā)送一個(gè)長(zhǎng)時(shí)間期待的request,當(dāng)服務(wù)器有材料response的時(shí)候立即斷掉,接著再發(fā)送一個(gè)新的request。 var initial = extractVariables(req.body); }); initial = extractVariables(req.body); 雖然程序還沒(méi)有瓦解,但我仍是沒(méi)有找到線索。在這里最佳實(shí)際也沒(méi)有措施捕獲那一行的錯(cuò)誤(手動(dòng)前端測(cè)試,單元測(cè)試,錯(cuò)誤處理,等等)。確實(shí),我應(yīng)該做負(fù)載測(cè)試,但是即使(測(cè)試)達(dá)到了競(jìng)爭(zhēng)前提同樣不能讓我覺(jué)得安全。 我的第一個(gè)反映是:NodeJS可以很好地處理負(fù)載,這是家喻戶曉的。50或100個(gè)用戶不可能讓系統(tǒng)崩潰。在得到Ryan Dahl的輔助之后,我們曉得這不是Node自身的問(wèn)題(后來(lái)的結(jié)果也驗(yàn)證了這一點(diǎn))。服務(wù)器開始返回異樣結(jié)果,用戶輸入“我的記錄是a、b和c”然而服務(wù)的答復(fù)是“你這個(gè)蠢貨,刪掉x、y和z這里的記錄是a、b和c。”即使可能斷定問(wèn)題的范疇并可以反復(fù)錯(cuò)誤,也簡(jiǎn)直不可能通過(guò)Node可憐的錯(cuò)誤處理和調(diào)試功效解決。采取的辦法就是下面的unix命令(是的,我對(duì)production進(jìn)行查問(wèn)) 咱們的體系用的是NodeJS,依據(jù)用戶輸入決議他確當(dāng)前狀況,例如用戶輸入“我正在等候更新這兩條記載”,服務(wù)器(基于時(shí)光戳檢討)會(huì)返回“你的記載已經(jīng)是最新的”或者“記錄xxx已更新為yyy。”(實(shí)際的過(guò)程會(huì)比這個(gè)更加龐雜,我們應(yīng)用了Redis共享變量和會(huì)話,并對(duì)Rails、mySQL、Redis跟Node之間的接口進(jìn)行保險(xiǎn)檢查)。(這個(gè)進(jìn)程)看上去十分簡(jiǎn)略,但當(dāng)事件不如預(yù)期的那樣時(shí),即便是簡(jiǎn)單的NodeJS 代碼也會(huì)成為噩夢(mèng)。今天惡夢(mèng)產(chǎn)生了。 當(dāng)初我要對(duì)你說(shuō)的是:你應(yīng)當(dāng)用過(guò) CoffeeScript并且可能對(duì)TameJS很在行。你可能是準(zhǔn)確的。我想理解第一次執(zhí)行NodeJS調(diào)用了哪些函數(shù),但這對(duì)我的公司是一個(gè)不用要的損失。在其余情形下,它可能帶來(lái)更重大的問(wèn)題(如果我在會(huì)話中錯(cuò)誤的使用了變量會(huì)如何?)。最重要的是,缺少真正好的錯(cuò)誤處理(在Rails,我們通過(guò)backtrace跟蹤錯(cuò)誤并把錯(cuò)誤發(fā)送給開發(fā)團(tuán)隊(duì))以及真正的調(diào)試(依附的是grep和less命令)讓我感到我們離好的開發(fā)差距很遠(yuǎn)。或者興許我應(yīng)當(dāng)更加警惕。 Trace: at EventEmitter.<anonymous>(/—/node/privacy.js:118:11) at EventEmitter.emit (events.js:81:20) process.on('uncaughtException', function (err) { console.log(['Caught exception', err]); console.trace(); }); app.all('/apps/:user_id/status', function(req, res, next) { -->// … 4個(gè)小時(shí)當(dāng)前(當(dāng)我翻到第503頁(yè)“ Temporarily Unavailable”,這時(shí)我的結(jié)合開創(chuàng)人對(duì)每一位掃興或好奇的用戶回復(fù)了致歉的郵件),我意識(shí)到問(wèn)題出在服務(wù)器將我的請(qǐng)求輸入(請(qǐng)求參數(shù))毛病地當(dāng)成隨機(jī)用戶請(qǐng)求參數(shù)。確實(shí)的說(shuō),服務(wù)器的設(shè)計(jì)只會(huì)對(duì)你的懇求返回你的相干信息,然而對(duì)你的要求發(fā)生了過(guò)錯(cuò)的理解。比方你說(shuō)“我愛(ài)好蘋果和甜瓜”,但是服務(wù)告知你“不要傻了,你喜歡的是芒果。”所以,固然(從平安的角度來(lái)說(shuō))所有都是安全的,但是成果是錯(cuò)的。為什么我的ExpressJS服務(wù)器不能懂得我的請(qǐng)求呢。我持續(xù)追蹤發(fā)明了下面的代碼: 相關(guān)的主題文章:
|