某618大促項目的復(fù)盤總結(jié)
一、前言
618期間上線一個活動項目。但上線不順利,當(dāng)天就出現(xiàn)了性能問題,接口超時,用戶無法打開網(wǎng)頁,最后不得的臨時下線。花了三天兩夜,重構(gòu)了后臺核心代碼,才讓活動進行下去。
回頭看了一下自己的時間記錄,從5月31號那天晚上8點25分開始準(zhǔn)備上線,發(fā)現(xiàn)異常,分析原因,重構(gòu)代碼,離開公司時已經(jīng)是6月2號的23點54,經(jīng)歷51小時29分,中間的睡眠時間不到5個小時,這已經(jīng)是爆發(fā)小宇宙了。
這一波剛過去了,一波未平另一波又起,由于活動的獎勵豐厚,大批羊毛黨聞風(fēng)而至,某寶上公開賣腳本的都有了,嚴(yán)重影響了正常用戶薅羊毛。
某客戶反饋說:我們別說薅羊毛了,現(xiàn)在是整頭羊都被他們牽走了!
接下來的幾天,又得和薅羊毛的腳本們斗智斗勇,直到活動結(jié)束。
而本文就對此做一次深度的復(fù)盤,在以后的項目中讓自己快活一點。
二、一份看似完美的項目總結(jié)
當(dāng)我們復(fù)盤項目過程時,能找到很多問題點,比如:
-
人力不足,需求過于復(fù)雜,開發(fā)和測試工作量大。
-
前后端開發(fā)、測試都是從其他團隊抽掉的,對當(dāng)前項目的業(yè)務(wù)和技術(shù)不熟悉。
-
跨團隊組建的臨時團隊,職責(zé)定義不清晰,項目管控不嚴(yán)格。
-
開發(fā)對項目的用到的技術(shù)不熟悉,沒有經(jīng)過原有項目成員的CodeReview。
-
測試通過太草率,壓測方案設(shè)計不合理。
....
列出問題后,很快就能一一寫出改進點。
-
從公司層面加強的整體項目安排,避免重復(fù)玩法的項目,資源投入到重點的幾個活動中。
-
加強團隊的能力培養(yǎng),總結(jié)文檔,供新人學(xué)習(xí)。
-
對于核心代碼進行CodeReview,遇到問題時,項目經(jīng)理協(xié)調(diào)資深開發(fā)協(xié)助解決。
-
將臨時組建團隊職責(zé)定義清晰,各負責(zé)人溝通清楚。
-
嚴(yán)格控制測試質(zhì)量,測試有上線的否決權(quán)。
...
這些總結(jié)看起來一點問題沒有,列出了問題,也列出了改進點,甚至可以當(dāng)成樣板去使用了,是不是咱們就這么結(jié)束了呢。
當(dāng)然不是, 它本身的說法沒有錯,錯在把問題的前提當(dāng)作問題的原因。
我們來看兩種表述。
-
下次我們要組建一個經(jīng)驗豐富的項目團隊,避免質(zhì)量問題發(fā)生。
-
當(dāng)下次我們面臨一個臨時組建,經(jīng)驗不足的項目團隊時,如何避免質(zhì)量問題發(fā)生。
這兩種表述的差異在哪?
前一種表述是因為我們“團隊”的原因,導(dǎo)致了本次質(zhì)量問題,所以我們要解決“團隊”的問題。
而后一種是我們的團隊就是臨時組建的,我們的開發(fā)、測試就是對新項目的業(yè)務(wù)和技術(shù)不熟悉,在這個前提下,才會出現(xiàn)質(zhì)量問題,那么在這個前提下,怎么避免質(zhì)量問題呢?
臨時組建,經(jīng)驗不足不是問題的原因,它們是出現(xiàn)問題的前提,這是客觀存在的。
這就好比我們說解決一個問題時,最快的方式是,我們不解決問題,解決出問題的人就行了。
在這里不就變成了,我們不解決問題,解決出問題的團隊就行了。
正是因為這個誤區(qū),我們很多時候一出現(xiàn)項目質(zhì)量問題,就把鍋甩給我們團隊的協(xié)作有問題,或者我們的項目時間緊張,然后一句下次改進就結(jié)束了。
這樣的萬能回答,看似一點沒錯,但往往就沒法落地了。
明明項目時間緊,新團隊協(xié)作經(jīng)驗不足本來就客觀的存在,沒有它就沒有問題,怎么可以當(dāng)作問題本身給解決掉呢。
1、質(zhì)量問題的關(guān)鍵原因
帶著這個前提,我們再回頭看前面的總結(jié),其實就能過濾出真正有價值的點了。
我們也可以這么問,問題是不能避免的,但為什么在項目過程中我們的性能問題沒有暴露出來?
三個角度:
-
從項目角度,沒有嚴(yán)格按項目流程來,特別是最后測試任務(wù)緊張,bug較多時,趕工給出了測試報告。
-
從開發(fā)角度,沒有找熟悉業(yè)務(wù)和技術(shù)的同學(xué)做CodeReview。
-
從測試角度,壓測方案設(shè)計不合理,不符合真實場景。
逐一分析下。
前面提到事故是后臺的性能問題,從項目角度,就算流程嚴(yán)謹(jǐn)也沒法暴露出性能問題,特別是在項目過程中,已暴露的風(fēng)險是前端人力不足,中間加了人手,從功能的角度,后端進度完全正常。
再看開發(fā)角度,這里我沒有提開發(fā)的經(jīng)驗不足,不是在推脫責(zé)任,這同我們作為一個臨時團隊對業(yè)務(wù)的經(jīng)驗不足一樣,它是一個客觀存在的前提。當(dāng)你接觸新項目,使用新技術(shù)時,經(jīng)驗不足是肯定存在的。
問題是在自身經(jīng)驗不足時,如何去完成任務(wù),那么和熟悉業(yè)務(wù)和技術(shù)的同學(xué)做CodeReview是主要的手段。
再從測試角度,功能測試是沒有問題的,但跟性能相關(guān)的壓測方案是有問題的,并且一開始就沒有引起正視。最開始的壓測方案是開發(fā)只出接口和參數(shù)文檔,直接丟給測試去壓,現(xiàn)在看來,這是錯誤的。
因此,這次質(zhì)量問題的關(guān)鍵總結(jié)如下。
當(dāng)下次我們面臨一個臨時組建,經(jīng)驗不足的項目團隊時,面對大流量的業(yè)務(wù)需求,開發(fā)們需要注意:
-
讓熟悉業(yè)務(wù)和技術(shù)的同學(xué)幫忙做CodeReview。
-
設(shè)計出符合業(yè)務(wù)場景的壓測方案。
這兩點就可以落地了,這也不是說項目管理上沒有改進的,而是優(yōu)先保證這兩點,能更有效的降低風(fēng)險。
CodeReview的技巧這里就不多少說,來談?wù)勎覀冏龅膸状螇簻y方案的改進。
2、三輪的壓測改進
-
單用戶,單接口,雙機壓測
-
隨機用戶,多接口,全量壓測
-
隨機用戶,功能分組接口,全量壓測
最開始壓測方案是用一個用戶,兩臺服務(wù)器,一個緩存分片做壓測,然后簡單的用服務(wù)器QPS的均值乘以線上部署機器數(shù)量當(dāng)作壓測結(jié)果。
這個方案如果是下圖左側(cè)的場景,調(diào)用鏈路上的服務(wù)器可以同時彈性擴展自然是可以的。
但要是右側(cè)的場景,調(diào)用鏈路上存在瓶頸,比如數(shù)據(jù)庫是一個節(jié)點,并且無法擴展,那就問題了。
同樣的,這次項目的問題就是Redis成為了一個單節(jié)點的瓶頸。另外由于用戶id是固定的,所以緩存很可能被重復(fù)使用,這樣就難以測試到頻繁創(chuàng)建緩存的場景。

在系統(tǒng)重構(gòu)后,改進了一種壓測方案,通過隨機用戶Id,批量輪詢接口,并且通過測試環(huán)境的彈性擴展,完全模擬線上的部署環(huán)境。
還通過加降級開關(guān),把入?yún)⒑戏ㄐ浴L(fēng)控、時效性校驗等臨時關(guān)閉,以便能讓壓測的請求貫穿整個主流程。
接著在這一方案的基礎(chǔ)上,通過對接口分組和偽造恰當(dāng)?shù)臄?shù)據(jù),編寫貼近真實的調(diào)用行為的腳本,再次做了壓測。
在執(zhí)行人員上,也經(jīng)歷了從開發(fā)提供數(shù)據(jù),測試全權(quán)負責(zé);到測試主導(dǎo),開發(fā)參與;再到開發(fā)主導(dǎo),測試協(xié)助的過程。
由此,壓測方案就越來越貼近真實場景,壓測結(jié)論自然就更加可信 。
3、高并發(fā)場景下的設(shè)計
前面談到了系統(tǒng)設(shè)計的不合理導(dǎo)致了本次性能問題,來分析下這里面的根本原因。
首先要理解的是,Redis集群是由多個分片構(gòu)成的,一條數(shù)據(jù)被寫到哪個分片里,是由key的hash值來離散的。

比如說,我們要在Redis里面緩存一批用戶信息,并且能通過ID來存取。
如果用Redis自帶的Hash表結(jié)構(gòu)寫法如下:
存:redis.hset("userMap",ID,userInfo)
讀:redis.hget("userMap",ID)
那么,因為key是固定的userMap,這意味著所有的用戶信息都會被寫到一個分片里。

而對于通常的分布式系統(tǒng)的設(shè)計,一個基本原則是:讓流量盡可能的被集群的機器平攤。
固定的key就無法利用分布式的優(yōu)勢了,并且如果并發(fā)量高,這就會讓一個分片去抗所有的流量,再加上如果用戶量數(shù)十萬,還有一次性讀取所有數(shù)據(jù)的操作,這樣就變成一場災(zāi)難了。
實際設(shè)計時,直接把整個Redis集群當(dāng)作一個Hash表的方式更加高效。
存:redis.set("userMap"+ID,userInfo)
讀:redis.get("userMap"+ID)
這里的key="userMap"+ID,ID不同key就被離散了,請求會集群平攤,從而充分發(fā)揮分布式系統(tǒng)的性能。
三、黑產(chǎn)和羊毛黨的問題
在項目上線后另一個沒重視的問題出現(xiàn)了,那就是大量的黑產(chǎn)和羊毛黨出現(xiàn),活動獎勵全被這些用腳本的人占據(jù)了。
對黑產(chǎn)的事前考慮太少了,僅做了簡單的風(fēng)控校驗,根本檢測不足異常用戶,導(dǎo)致黑產(chǎn)可以通過腳本大量刷接口。
這里的經(jīng)驗有兩點:
-
對包含現(xiàn)金、現(xiàn)金等價物或高價值獎勵的活動,要有面對黑產(chǎn)的心理預(yù)期。
-
在大公司,專業(yè)的事情找專業(yè)的人做,基于業(yè)務(wù)場景,提前跟風(fēng)控團隊溝通好。
對于第一點,基本上只要值點錢的活動,黑產(chǎn)肯定跑不了,空手套白狼,搶到就是賺到,不妨想想如果你是黑產(chǎn),結(jié)合下業(yè)務(wù)場景,你會怎么來刷自己的系統(tǒng)。
基于第一點,公司沒有風(fēng)控團隊那就只能自己做了,而一般上點規(guī)模的公司都有自己的風(fēng)控團隊,利用好現(xiàn)成資源。
風(fēng)控主要考慮兩方面:
-
有風(fēng)控團隊的,接入他們的通用風(fēng)控模型。
-
針對項目的業(yè)務(wù)場景,定制化一些風(fēng)控模型。
通用風(fēng)控模型基本是通過新老賬號、異地登錄、人機識別等等用戶行為建立的用戶畫像,通過離線計算和實時校驗來處理。
定制化模型視情況而定,比如拉一個單獨的小黑戶,放進去的用戶不能參與這個活動等等。
被攔截的用戶一般是走驗證碼或直接拉黑,對于后者,別忘了和客服的妹子們打好招呼,準(zhǔn)備下話術(shù)應(yīng)對客訴。
四、結(jié)語
最后總結(jié)下項目的經(jīng)驗。
首先是前提:
-
當(dāng)你的面前的是一個臨時組建,對現(xiàn)在項目經(jīng)驗不足的項目團隊時。
-
當(dāng)你面臨一個大流量,包含現(xiàn)金或等價物的活動時。
請務(wù)必做好這三點:
-
找熟悉本項目的業(yè)務(wù)和技術(shù)的開發(fā)參與方案的設(shè)計和CodeReview。
-
請開發(fā)主動參與壓測任務(wù),設(shè)計壓測方案,注意盡可能模擬真實場景。
-
做好應(yīng)對黑產(chǎn)的心理準(zhǔn)備,直到大促活動結(jié)束。
來自于,一個連續(xù)加班51小時29分,被用戶吐槽整只羊都被人家牽走了的開發(fā)。
浙公網(wǎng)安備 33010602011771號