大廠是怎樣對(duì)待線上故障的?
本文轉(zhuǎn)載自微信公眾號(hào)「碼磚雜役」,作者我不想種地 。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼磚雜役公眾號(hào)。
軟件測(cè)試有句名言:測(cè)試只能證明缺陷的存在,而不能證明產(chǎn)品沒有缺陷。
為了保障安全,我們引入規(guī)范和流程,小心翼翼設(shè)計(jì)編碼,如履薄冰測(cè)試發(fā)布,軟件的結(jié)構(gòu)和實(shí)現(xiàn)非常大的比重服務(wù)于穩(wěn)定性,然而,縱使我們窮盡所能,也只能最大限度減少故障,而終究無法徹底消除故障。
企業(yè)為了保障交付和運(yùn)營(yíng)質(zhì)量,往往會(huì)設(shè)置安全標(biāo)準(zhǔn),制定事故懲罰規(guī)則,而這加劇了交付效率和系統(tǒng)安全的沖突。軟件工程師搖身一變成了跟外科醫(yī)生一樣的高危行業(yè)從業(yè)者,我們被灌輸了很多跟安全生產(chǎn)相關(guān)的知識(shí),我們的認(rèn)知被教育成某個(gè)樣子,我們對(duì)于線上故障的觀念根深蒂固而又深信不疑。
筆者在網(wǎng)游和互聯(lián)網(wǎng)大廠工作過,它們對(duì)于線上故障有著截然不同的態(tài)度,這些不同對(duì)我造成了強(qiáng)烈的沖擊,可以說我剛被教育成某個(gè)樣子,等換了一份工作,又被教育成另一個(gè)樣子,所以,我的認(rèn)知在不斷變化,而這些經(jīng)歷和變化使我相比別人有更多的思考和感悟。
如果說對(duì)于這個(gè)話題,我跟剛參加工作時(shí)有什么不同,那就是我逐漸意識(shí)到事情沒有絕對(duì),意識(shí)到我的認(rèn)知不一定正確,而這或許是通往正確的道路。
所以,我把所見所感記錄下來,力求客觀呈現(xiàn)原貌,既不是要主張什么,也不是要批評(píng)什么,因?yàn)?,相比于觀點(diǎn),事實(shí)才是更重要的,我更愿意傾聽大家的觀點(diǎn)。
一、網(wǎng)絡(luò)游戲
我讀研的時(shí)候在某狐做實(shí)習(xí),在當(dāng)時(shí),某狐就是大廠,后來火狐工作室獨(dú)立上市,對(duì),就是納市上市的CY。
我在《TLBB》做了一年半的游戲開發(fā),這款游戲當(dāng)時(shí)非常成功,PCU超80萬,為公司貢獻(xiàn)超過90%的營(yíng)收。
TLBB通過流程管理軟件管理需求和缺陷,這在當(dāng)時(shí)非常先進(jìn)。
策劃提需求寫文檔,程序開發(fā)功能,提測(cè),然后流程流轉(zhuǎn)到測(cè)試那里。
測(cè)試的考核按BUG計(jì)件,而提測(cè)后的BUG數(shù)也會(huì)影響程序績(jī)效。這樣的制度設(shè)計(jì)能確保程序提測(cè)前做充分自測(cè),從而去降低缺陷數(shù),程序是功能的開發(fā)者,是白盒測(cè)試的最佳實(shí)施者,他似乎有一種天然的感知,預(yù)感那里會(huì)有可能出現(xiàn)問題,而且為了方便自測(cè),他會(huì)想法設(shè)法去開發(fā)一些輔助測(cè)試功能,這又會(huì)提升測(cè)試的效率。
而測(cè)試為了績(jī)效,也會(huì)竭盡所能去查找缺陷。但這個(gè)制度的一個(gè)副作用就是程序和測(cè)試關(guān)系經(jīng)常很緊張,程序覺得地位不高,經(jīng)常被測(cè)試干。
CTO為TLBB服務(wù)器制定了幾條制度:
1. 簡(jiǎn)單至上,設(shè)計(jì)上直來直去,不過度設(shè)計(jì);編碼上不準(zhǔn)用模板、不準(zhǔn)用STL、不讓用C++高級(jí)特性(比如異常、placement new等)。
2. 注重防御,安全優(yōu)先于效率,任何一個(gè)函數(shù)都嵌入ENTER_FUNCTION和LEAVE_FUNCTION宏,多判斷多檢查,盡量不崩。
這種設(shè)計(jì)獲得的一個(gè)顯著好處就是項(xiàng)目代碼簡(jiǎn)單,門檻不高,應(yīng)屆畢業(yè)兩禮拜就能愉快上手,壞處就是程序性能不高,開發(fā)者天天跟數(shù)組和指針打交道,技術(shù)提不高,以致工作一年多之后發(fā)現(xiàn)看不懂開源項(xiàng)目,感覺自己是個(gè)智障。
游戲要求快速迭代,每周都會(huì)發(fā)版本,所以,從特征分支往主干merge代碼有時(shí)間窗口,窗口關(guān)閉期內(nèi)只能fix bug,新人前半年提交代碼,會(huì)有人做review,相當(dāng)于給兒童自行車后輪裝2個(gè)支撐輪,之后便能自主提交,至于靜態(tài)掃描、代碼門禁,不好意思,沒聽過。得益于良好的制度設(shè)計(jì)和測(cè)試環(huán)節(jié),TLBB服務(wù)器總體平穩(wěn),小問題偶發(fā)。
公司對(duì)線上故障有定級(jí),但公司不怎么講,所以大家感覺也不怎么強(qiáng),要是某個(gè)程序不開眼捅了簍子,考核會(huì)受一些影響,次數(shù)多了,便會(huì)被貼不靠譜的標(biāo)簽,只能專業(yè)打雜。
后面我去了WMSJ,這個(gè)公司是幾個(gè)清華學(xué)生做起來的。
07年,《WMSJ》憑借在3D上的卓越表現(xiàn)驚艷問世,隨后又連續(xù)推出幾款不錯(cuò)的游戲,成立三年便赴納市上市了。
那時(shí)候CHI老板意氣風(fēng)發(fā),千金買馬骨,給應(yīng)屆生開出了1萬5-1萬8的高薪,哪年校招我碰上了,但是他們要求很高,我一面就陣亡,我另一個(gè)研究生同學(xué)去霸面被轟了出來。
這家公司的第一代程序員水平很高,至今我仍然認(rèn)為是我工作中接觸到最才華橫溢的程序員,從客戶端引擎到UI到數(shù)據(jù)庫(kù),整個(gè)游戲前后端+引擎,全部自研。因我做服務(wù)器,所以無法評(píng)價(jià)引擎、客戶端技術(shù)。
光論服務(wù)器,它們的技術(shù)水平是很高的,當(dāng)我在CY的時(shí)候,大家一直在Y,WM的大世界(無縫地圖)到底是怎么做的呢?TLBB是分片地圖,當(dāng)我看完WMSJ服務(wù)器的代碼,我被震撼了,那是一個(gè)非常精巧的設(shè)計(jì),后來大熱的BigWorld引擎在服務(wù)器設(shè)計(jì)上跟WM有共通之處。
相比TLBB,WMSJ完全是無規(guī)則的,沒有任何明文規(guī)定禁止做什么,應(yīng)該怎么做,只要編譯能通過,運(yùn)行不報(bào)錯(cuò),就哦了。編碼規(guī)范?交叉review?不需要的,代碼門禁?封版?不存在的,線上故障處罰?沒有的事。
但入職后一個(gè)半月,我除了看代碼,沒有任何工作要做,我一度懷疑領(lǐng)導(dǎo)對(duì)我有看法,借老婆生小孩的機(jī)會(huì)請(qǐng)1個(gè)月假表達(dá)不滿,領(lǐng)導(dǎo)問我為何請(qǐng)這么長(zhǎng)的假,我說反正也沒事干,領(lǐng)導(dǎo)說,你沒看新來的那個(gè)清華畢業(yè)生已經(jīng)氣定神閑的看了2個(gè)多月代碼了嗎?讓我淡定,組織馬上就有任務(wù)安排給我了。
通過這個(gè)項(xiàng)目,我學(xué)會(huì)到epoll模型、學(xué)會(huì)了多線程、學(xué)會(huì)了通過消息機(jī)制解耦、學(xué)會(huì)了COW、學(xué)會(huì)了lazy evaluation、學(xué)會(huì)了真正的OOP和GP(做抽象、泛化和擴(kuò)展性)。
其中最大的思維碰撞來自于容錯(cuò),之前TLBB的編碼會(huì)做大量的容錯(cuò)處理,比如簡(jiǎn)單的get函數(shù)也會(huì)有enter_function/leave_function宏,會(huì)對(duì)指針判空,參數(shù)做合法性校驗(yàn),會(huì)對(duì)返回值做檢查,會(huì)log error等,大量的容錯(cuò)代碼淹沒了功能代碼,導(dǎo)致完成同樣的功能,需要多得多的代碼。
但WMSJ的做法截然相反,它廣泛的使用斷言,函數(shù)專注于功能邏輯,對(duì)調(diào)用者有期望,如果不符合要求,不叨逼,直接崩,風(fēng)格很硬朗,代碼很緊湊。
我工作以來接受的教育不是這樣的,這讓我困惑,我找到了GameServer的主要開發(fā)者C總(技術(shù)VP、清華畢業(yè)的,他一個(gè)人寫了超過60%的代碼),公認(rèn)的WMSJ最強(qiáng)架構(gòu)師(不是我封的)。
我說:“TL服務(wù)器的風(fēng)格是面向失敗編程,能不崩就不崩,這樣,程序才能有足夠的韌性。WM服務(wù)器這樣做不對(duì)吧!”
C總回答:“不是這樣的,容錯(cuò)不是越多檢查越多日志越好,核查只應(yīng)該在邊界進(jìn)行,函數(shù)的實(shí)現(xiàn)者和調(diào)用者遵從某種契約,過多的防御并不能體現(xiàn)面向失敗編程的思想,也不利于構(gòu)建健壯的程序。崩會(huì)及早暴露問題,該崩不崩只會(huì)把錯(cuò)誤埋得更深,導(dǎo)致缺陷更難定位,最終程序會(huì)變成藏污納垢的混亂場(chǎng),從而變得更加脆弱。”
“依賴假設(shè),在代碼被修改后,容易引起問題,線上故障是應(yīng)該極力避免的。”我當(dāng)時(shí)的認(rèn)知沒法接受他的解釋,而是嘗試說服他。
C總說:“assert在編譯debug版本的時(shí)候起作用,而發(fā)布的時(shí)候,編譯的是release版本,這其實(shí)是內(nèi)嚴(yán)外松,在開發(fā)階段及早暴露問題,上線之后才能更穩(wěn)定,而且你遵照這樣的規(guī)則編寫程序會(huì)更清晰健壯,你多看幾個(gè)開源項(xiàng)目就明白了。”
我當(dāng)時(shí)被“你多看幾個(gè)開源就明白了”給噎住了,因?yàn)槲耶?dāng)時(shí)確實(shí)沒看過什么開源項(xiàng)目,以致很多年以后,碰到同樣的辯論,我也會(huì)用同樣的一句話噎人。
WMSJ無規(guī)則,新人看一個(gè)月代碼,這些事情,我絲毫沒有夸張,所以,你看,雖然同為游戲公司(且為同種類型游戲MMORPG),但TL和WM采取了截然不同的策略,且在當(dāng)時(shí)都取得了成功。
當(dāng)年做游戲的時(shí)候,我們的開發(fā)任務(wù)很重,一般服務(wù)器組也就5-7人,2年內(nèi)要寫50萬行左右的C++代碼,4萬行C++每人年,這個(gè)工作量是很大的,所以,其實(shí)很難走很重的研發(fā)流程,可以說,嚴(yán)格按流程走,基本上游戲沒上線之前就死了。
但沒走流程并不意味游戲程序員技術(shù)差,恰恰相反,大劑量的編碼訓(xùn)練,往往使得大家編碼水平較高,而且普遍很務(wù)實(shí)。
還有一個(gè)有意思的事情就是,我們?cè)?jīng)按照銀行系統(tǒng)的要求去搞數(shù)據(jù)庫(kù),比如支持事務(wù)、支持回滾,發(fā)現(xiàn)既麻煩又別扭,直到有一天,我們頓悟,發(fā)現(xiàn)我們想多了,其實(shí)人最怕想多,也最容易想多,文科生一想多就容易出家,藝術(shù)家一想多就容易自殺,最終我們參考伯克利DB只用簡(jiǎn)單的3千行C++就寫出一個(gè)Cache DB,其實(shí)它也夠用了。
做游戲的時(shí)候,另一個(gè)體會(huì)就是我們?cè)?jīng)在穩(wěn)定性設(shè)計(jì)上投入了很多精力,或者公司運(yùn)營(yíng)對(duì)穩(wěn)定性提出了較高的要求,我們?cè)鴪?jiān)信這些是必要的,直到有一天,我們發(fā)現(xiàn),事情可能并非如此。
比如有個(gè)游戲在封測(cè)期間,一天晚上宕機(jī)十幾次,但瘋狂的玩家竟然一邊在論壇破口大罵,一邊癡心不改的等待重啟恢復(fù),而統(tǒng)計(jì)數(shù)據(jù)表明,這款游戲的流失率很低,玩家好像真正在乎的只是游戲的趣味性,我們?cè)e(cuò)誤的以為穩(wěn)定性是留存的大敵。
另一個(gè)例子是,某游戲因?yàn)槌绦蛉毕荩┒幢煌婕依?,而這個(gè)事情暴露后,消息在論壇、網(wǎng)絡(luò)傳播,導(dǎo)致大量吃瓜和看熱鬧的新玩家涌入,一個(gè)漏洞變成一個(gè)很好的運(yùn)營(yíng)廣告,我們覺得出現(xiàn)故障,影響玩家體驗(yàn),再給玩家發(fā)補(bǔ)助,這只是不得已的補(bǔ)救,但調(diào)查發(fā)現(xiàn),這竟然是玩家喜聞樂見的,能極大提升話題熱度和玩家活躍度。
二、互聯(lián)網(wǎng)
說完游戲經(jīng)歷,說一下互聯(lián)網(wǎng)經(jīng)歷。
我先后在TX和某里干過,先說說TX - WX,雖然WX的做法不代表整個(gè)TX公司的做法,但我覺得還是能反映一些問題,可供參考。
我在WX做過一段時(shí)間搜索的工程,就是WX 搜一搜,WX后臺(tái)的服務(wù)基本上都是基于svrkit框架開發(fā)的,svrkit是一個(gè)RPC框架(開源名phxRPC),負(fù)載均衡、錯(cuò)誤重試等框架都做了,基于該框架做應(yīng)用只需要專注于業(yè)務(wù)邏輯。
當(dāng)時(shí)WX搜索北京雖然有差不多60人,但絕大多數(shù)人都是做算法的,做工程的只有3個(gè),2個(gè)做搜一搜,一個(gè)做看一看,我是其中一個(gè)。
要說TX怎么也是一個(gè)大廠了吧,按理說,研發(fā)流程應(yīng)該也是很齊整,但坦白說,我們要上線一個(gè)應(yīng)用真的沒有那么麻煩,我們甚至沒有專門的測(cè)試,我開發(fā)完一個(gè)功能,可能先灰度一臺(tái)機(jī)器,觀察5分鐘,撈log看看,沒有明顯異常,然后我就灰度1%的機(jī)器,再觀察1個(gè)小時(shí),如果沒有問題,我就灰度10%,再觀察半個(gè)小時(shí),如果還沒有問題,我就梭哈了。
你看,一個(gè)更新,整個(gè)流程2個(gè)小時(shí)就可以搞定,是不是很麻溜?
那要是有問題怎么辦呢?有問題,速度回滾,出故障,那就拉出來打板子,但這個(gè)板子其實(shí)一般不要命,有點(diǎn)自罰三杯的味道。
這個(gè)事,其實(shí)我一直不敢對(duì)外說,因?yàn)槟氵@樣說出來,會(huì)覺得丟人,會(huì)覺得low,一點(diǎn)都不高大上,跟同行見了面都不好意思打招呼。
WX一個(gè)技術(shù)主管跟我說過,他經(jīng)常因?yàn)榫€上事故被通報(bào)批評(píng),但沒被罰過錢,有一次WX支付的故障,被大領(lǐng)導(dǎo)盤問,但即使這樣,WX也沒有想過通過加重流程去降低故障率。
他說這是WX的一個(gè)選擇,WX認(rèn)為業(yè)務(wù)失去快速迭代能力是不能承受之重,雖然線上故障有時(shí)候也會(huì)造成嚴(yán)重的后果,但WX對(duì)線上故障的容忍度較高,穩(wěn)定性和敏捷性是矛盾的兩級(jí),很難兼顧,WX傾向了敏捷。
可見,TX,或者說WX并不是不清楚穩(wěn)定生產(chǎn)的重要性,也不是不知道通過加重流程可以減少故障,只是在綜合各方因素后,他們選擇了保業(yè)務(wù)快速迭代,敏捷是互聯(lián)網(wǎng)的命根子,不能丟。
有人跟我講了另一個(gè)WX的故事,WX基本上在立項(xiàng)后幾個(gè)月后推出了,因?yàn)楹艽颐?,其?shí)后臺(tái)有很多問題,比如內(nèi)存泄漏,但他們沒有馬上選擇去解決這個(gè)問題(或者說正面剛),他們選擇了繞過問題,在服務(wù)100次后,進(jìn)程自動(dòng)重啟,從而完美的解決了這個(gè)問題,這段代碼后來被一個(gè)實(shí)習(xí)生review出來,把100改成1000,性能提升了很多倍。
說到這里,很多人一定以為WX的技術(shù)很弱,WX工程很渣,這跟事實(shí)不符,大家可以去TX開源看看,里面有大量WX開源的項(xiàng)目,我認(rèn)為那些優(yōu)秀的開源項(xiàng)目,是最好的證明。
再說說某里,某里則是完全另一番景象,某里行癲把穩(wěn)定性比喻成木桶的底板,如果穩(wěn)定性出問題,則滴水不留,所以,要求工程師在設(shè)計(jì)和開發(fā)軟件的時(shí)候,堅(jiān)持底板思維。
某里的開發(fā)人員每年都要過安全生產(chǎn)的考試,每年618、雙11、雙12、春節(jié)、38節(jié)、甚至兩hui期間,TB都要提前很久封版,特別是雙11,至少1個(gè)半月封版,封版期間任何更新都要走特批,所以,留給開發(fā)的時(shí)間窗口其實(shí)非常非常短。
每年都會(huì)集中培訓(xùn)安全生產(chǎn)常識(shí),每年都會(huì)逐級(jí)開會(huì)強(qiáng)調(diào)安全生產(chǎn)重要性,安全生產(chǎn)大于天,這根神經(jīng)絕不能松,都會(huì)提前做各種應(yīng)急預(yù)案,假設(shè)XX情況出現(xiàn)要YY辦,制作成手冊(cè),到時(shí)候出現(xiàn)異常,遵照?qǐng)?zhí)行,這些事情耗費(fèi)了大量的人力財(cái)力。
但實(shí)際情況就是99.999%沒用,完全是瞎忙活,大促期間都是集體出動(dòng),熬夜守班,再一起擺pos熬造型發(fā)朋友圈,你可能會(huì)說,這些是完全必要的,為的就是萬一出現(xiàn)萬一,有兜底方案,對(duì),你說的對(duì),這樣的邏輯沒人會(huì)不懂,某里人也是這么想的。
但任何事情都有一個(gè)度,這個(gè)度可視為一個(gè)平衡點(diǎn),過猶不及,這是最樸素的道理。
為什么某里對(duì)安全生產(chǎn)這么看重,當(dāng)然,首先,他們會(huì)從他們業(yè)務(wù)的特殊性進(jìn)行一波分析,比如把TB自詡為國(guó)家基礎(chǔ)設(shè)施,跟水電煤氣一樣,從各個(gè)角度闡述極端重要性。
但其實(shí),最根本的原因大家沒說,那就是誰出問題,誰3.25,而且還連坐,一出事基本上在,某里就沒法做下去,處罰很重,而且真的會(huì)處罰很高級(jí)別的領(lǐng)導(dǎo)。
所以,在安全生產(chǎn)的“大是大非”面前,沒人敢大意,沒人敢做違背流程挑戰(zhàn)zz正確的事情,結(jié)果上,某里的服務(wù)穩(wěn)定性是否比TX強(qiáng),我不知道,但迭代效率上,肯定是慢了很多。
最有意思的是,如果你跟某里人(特別是老人)討論安全生產(chǎn)的問題,你會(huì)發(fā)現(xiàn)他們觀點(diǎn)出奇的一致,他們堅(jiān)信安全生產(chǎn)責(zé)任大于天,應(yīng)該堅(jiān)持零容忍,越嚴(yán)越好,但事情是否真的應(yīng)該這樣辦?我不知道,但至少同為互聯(lián)網(wǎng)的TX不是這樣,而TX的業(yè)務(wù)不也發(fā)展的好好的嗎?
我們很容易舉出業(yè)務(wù)特殊性,比如電商可以舉例說某個(gè)心臟病人因?yàn)榫W(wǎng)購(gòu)救命藥下不了單導(dǎo)致喪命,如果你制造了這個(gè)bug,相當(dāng)于間接殺人,是不是很嚇人?比如DD,它也可以這樣說,因?yàn)锳PP出問題,導(dǎo)致打車的女孩不能及時(shí)呼救,被強(qiáng)奸繼而被害,是不是也很恐怖?
其實(shí)這樣的例子,游戲行業(yè)也可以舉出來,比如某個(gè)孩子因?yàn)橛螒蚩ǜ北?,?dǎo)致一怒之下,點(diǎn)了房子,導(dǎo)致滅門。
所以,沒必要用這樣的例子來強(qiáng)調(diào)業(yè)務(wù)的特殊性,因?yàn)槭擒浖€是要尊重軟件常識(shí),回歸本質(zhì),但業(yè)務(wù)有沒有特殊性?有!而且我們必須正視。
比如電信業(yè)務(wù),我們要把軟件部署到別人的數(shù)據(jù)中心,我們要更新別人機(jī)房的程序有很多限制,這個(gè)跟互聯(lián)網(wǎng)的軟件確實(shí)有很大的不同。
這對(duì)我們的軟件提出了更高的穩(wěn)定性要求,這是顯而易見的,但我們?nèi)菀走^于強(qiáng)調(diào)安全性,而忽視了對(duì)生產(chǎn)效率的影響,而對(duì)生產(chǎn)效率的副作用可能遠(yuǎn)比我們?nèi)魏我粋€(gè)人想象的都大。
JD大東子曾總結(jié)幾個(gè)商業(yè)成功的關(guān)鍵因素,其中之一,就是你可以做到更低的成本,或者做到更高的效率,所以,對(duì)于商業(yè)公司而言,生產(chǎn)效率,對(duì)應(yīng)到軟件的開發(fā)效率,成本控制,其實(shí)遠(yuǎn)比我們想象的重要,而我們卻容易掉進(jìn)顧彼失此的陷阱。
小結(jié)
我前面說我會(huì)闡述事實(shí),而非陳述觀點(diǎn),很抱歉騙了你,其實(shí)完全沒有觀點(diǎn)的文章不值得寫,史書還有觀點(diǎn)呢,那筆者的觀點(diǎn)到底是什么呢?
在一個(gè)個(gè)經(jīng)歷的故事里。






















