秒殺特點(diǎn)及思路?
短時(shí)間內(nèi),大量用戶(hù)涌入,集中讀和寫(xiě)有限的庫(kù)存。
盡量將請(qǐng)求攔截在系統(tǒng)上游(越上游越好);讀多寫(xiě)少的多使用緩存(緩存抗讀壓力);
從分層角度理解?
層層攔截,將請(qǐng)求盡量攔截在系統(tǒng)上游,避免將鎖沖落到數(shù)據(jù)庫(kù)上。
第一層:客戶(hù)端優(yōu)化
產(chǎn)品層面,用戶(hù)點(diǎn)擊“查詢(xún)”或者“購(gòu)票”后,按鈕置灰,禁止用戶(hù)重復(fù)提交請(qǐng)求;JS層面,限制用戶(hù)在x秒之內(nèi)只能提交一次請(qǐng)求,比如微信搖一搖搶紅包?;究梢詳r截80%的請(qǐng)求。
第二層:站點(diǎn)層面的請(qǐng)求攔截(nginx層,寫(xiě)流控模塊)
怎么防止程序員寫(xiě)for循環(huán)調(diào)用,有去重依據(jù)么? IP? cookie-id? …想復(fù)雜了,這類(lèi)業(yè)務(wù)都需要登錄,用uid即可。在站點(diǎn)層面,對(duì)uid進(jìn)行請(qǐng)求計(jì)數(shù)和去重,甚至不需要統(tǒng)一存儲(chǔ)計(jì)數(shù),直接站點(diǎn)層內(nèi)存存儲(chǔ)(這樣計(jì)數(shù)會(huì)不準(zhǔn),但最簡(jiǎn)單,比如guava本地緩存)。一個(gè)uid,5秒只準(zhǔn)透過(guò)1個(gè)請(qǐng)求,這樣又能攔住99%的for循環(huán)請(qǐng)求。對(duì)于5s內(nèi)的無(wú)效請(qǐng)求,統(tǒng)一返回錯(cuò)誤提示或錯(cuò)誤頁(yè)面。
這個(gè)方式攔住了寫(xiě)for循環(huán)發(fā)HTTP請(qǐng)求的程序員,有些高端程序員(黑客)控制了10w個(gè)肉雞,手里有10w個(gè)uid,同時(shí)發(fā)請(qǐng)求(先不考慮實(shí)名制的問(wèn)題,小米搶手機(jī)不需要實(shí)名制),這下怎么辦,站點(diǎn)層按照uid限流攔不住了。
第三層:服務(wù)層攔截
方案一:寫(xiě)請(qǐng)求放到隊(duì)列中,每次只透有限的寫(xiě)請(qǐng)求到數(shù)據(jù)層,如果成功了再放下一批,直到庫(kù)存不夠,隊(duì)列里的寫(xiě)請(qǐng)求全部返回“已售完”。
方案二:或采用漏斗機(jī)制,只放一倍的流量進(jìn)來(lái),多余的返回“已售完”,把寫(xiě)壓力轉(zhuǎn)換成讀壓力。讀請(qǐng)求,用cache,redis單機(jī)可以抗10W QPS,用異步線程定時(shí)更新緩存里的庫(kù)存值。 、
還有提示“模糊化”,比如火車(chē)余票查詢(xún),票剩了58張,還是26張,你真的關(guān)注么,其實(shí)我們只關(guān)心有票和無(wú)票。
第四層:數(shù)據(jù)庫(kù)層
瀏覽器攔截了80%,站點(diǎn)層攔截了99.9%并做了頁(yè)面緩存,服務(wù)層又做了寫(xiě)請(qǐng)求隊(duì)列與數(shù)據(jù)緩存,每次透到數(shù)據(jù)庫(kù)層的請(qǐng)求都是可控的。 db基本就沒(méi)什么壓力了,通過(guò)自身鎖機(jī)制來(lái)控制,避免出現(xiàn)超賣(mài)。
從架構(gòu)角度理解?
高性能
動(dòng)靜分離 秒殺過(guò)程中你是不需要刷新整個(gè)頁(yè)面的,只有時(shí)間在不停跳動(dòng)。這是因?yàn)橐话愣紩?huì)對(duì)大流量的秒殺系統(tǒng)做系統(tǒng)的靜態(tài)化改造,即數(shù)據(jù)意義上的動(dòng)靜分離。動(dòng)靜分離三步走:
數(shù)據(jù)拆分;靜態(tài)緩存;數(shù)據(jù)整合。
熱點(diǎn)優(yōu)化 數(shù)據(jù)的熱點(diǎn)優(yōu)化與動(dòng)靜分離是不一樣的,熱點(diǎn)優(yōu)化是基于二八原則對(duì)數(shù)據(jù)進(jìn)行了縱向拆分,以便進(jìn)行針對(duì)性地處理。熱點(diǎn)識(shí)別和隔離不僅對(duì)“秒殺”這個(gè)場(chǎng)景有意義,對(duì)其他的高性能分布式系統(tǒng)也非常有參考價(jià)值。
系統(tǒng)優(yōu)化
減少序列化:減少 Java 中的序列化操作可以很好的提升系統(tǒng)性能。序列化大部分是在 RPC 階段發(fā)生,因此應(yīng)該盡量減少 RPC 調(diào)用,一種可行的方案是將多個(gè)關(guān)聯(lián)性較強(qiáng)的應(yīng)用進(jìn)行 “合并部署”,從而減少不同應(yīng)用之間的 RPC 調(diào)用(微服務(wù)設(shè)計(jì)規(guī)范)
直接輸出流數(shù)據(jù):只要涉及字符串的I/O操作,無(wú)論是磁盤(pán) I/O 還是網(wǎng)絡(luò) I/O,都比較耗費(fèi) CPU 資源,因?yàn)樽址枰D(zhuǎn)換成字節(jié),而這個(gè)轉(zhuǎn)換又必須查表編碼。所以對(duì)于常用數(shù)據(jù),比如靜態(tài)字符串,推薦提前編碼成字節(jié)并緩存,具體到代碼層面就是通過(guò) OutputStream() 類(lèi)函數(shù)從而減少數(shù)據(jù)的編碼轉(zhuǎn)換;另外,熱點(diǎn)方法toString()不要直接調(diào)用ReflectionToString實(shí)現(xiàn),推薦直接硬編碼,并且只打印DO的基礎(chǔ)要素和核心要素
裁剪日志異常堆棧:無(wú)論是外部系統(tǒng)異常還是應(yīng)用本身異常,都會(huì)有堆棧打出,超大流量下,頻繁的輸出完整堆棧,只會(huì)加劇系統(tǒng)當(dāng)前負(fù)載。可以通過(guò)日志配置文件控制異常堆棧輸出的深度
去組件框架:極致優(yōu)化要求下,可以去掉一些組件框架,比如去掉傳統(tǒng)的 MVC 框架,直接使用 Servlet 處理請(qǐng)求。這樣可以繞過(guò)一大堆復(fù)雜且用處不大的處理邏輯,節(jié)省毫秒級(jí)的時(shí)間,當(dāng)然,需要合理評(píng)估你對(duì)框架的依賴(lài)程度
高可用
流量削峰
答題:答題目前已經(jīng)使用的非常普遍了,本質(zhì)是通過(guò)在入口層削減流量,從而讓系統(tǒng)更好地支撐瞬時(shí)峰值。MQ: 最為常見(jiàn)的削峰方案是使用消息隊(duì)列,通過(guò)把同步的直接調(diào)用轉(zhuǎn)換成異步的間接推送緩沖瞬時(shí)流量。過(guò)濾
Plan B: 為了保證系統(tǒng)的高可用,必須設(shè)計(jì)一個(gè) Plan B 方案來(lái)進(jìn)行兜底