《吊打面試官》系列-秒殺系統設計

你知道的越多,你不知道的越多前端

點贊再看,養成習慣nginx

GitHub上已經開源 https://github.com/JavaFamily 有一線大廠面試點腦圖和我的聯繫方式,歡迎Star和指教git

前言

Redis在互聯網技術存儲方面使用如此普遍,幾乎全部的後端技術面試官都要在Redis的使用和原理方面對小夥伴們進行360°的刁難。程序員

做爲一個在互聯網公司面一次拿一次Offer的麪霸,戰勝了無數競爭對手,每次都只能看到無數落寞的身影失望的離開,略感愧疚(請容許我使用一下誇張的修辭手法)。github

因而在一個寂寞難耐的夜晚,我痛定思痛,決定開始寫《吊打面試官》系列,但願能幫助各位讀者之後面試勢如破竹,對面試官進行360°的反擊,吊打問你的面試官,讓一同面試的同僚瞠目結舌,瘋狂收割大廠Offer!web

絮叨

以前寫了不少Redis相關的知識點,我又大概回頭看了下,除了比較底層的東西沒寫很深以外,我基本上的點都提到過了,我相信若是隻是爲了應付面試應該是夠了的,可是若是你想把它們真正的吸取納爲己用,仍是須要大量的知識積累,和不少實際操做的。面試

就我本身而言Redis在開發過程當中實在用得太廣泛了,熱點數據的存儲啊,總體性能的提高啊都會用到,可是就像我說的技術就是一把雙刃劍,使用它們隨之而來的問題也會不少的,我在老東家雙十二就遇到緩存雪崩問題讓總體服務宕機3分鐘,相必你們都知道阿里今年的雙十一數據了,那三分鐘在這種時候到底值多少錢?真的不敢想象。redis

Redis的廣泛我就拿掘金我本身的認知舉例,不知道對不對,可是目測是對的。算法

你們看到問題所在了麼?是的熱門的讚的數據不是最新的,我盲猜一波上面的熱門文章是緩存。失效時間應該是幾十分鐘的,爲啥這麼作呢?數據庫

熱門文章是你們共同都會看到的,也就是熱點數據,在那作緩存,他是不須要那麼高的實時性的,那下面的文章列表是最新發布的文章,有高實時性的特色,你們訪問多的放在緩存還能夠給DB減小壓力,我也不知道掘金是否是這麼作的哈,反正道理是這麼個道理了。

那什麼場景是使用Redis比較複雜的場景,並且須要大量中間件業務邏輯去配合的呢?

秒殺!是的就是今天的主題秒殺,我就用我本身的思路帶你們一塊兒看一下,設計一個秒殺從前到後,從內到外到底要技術人員作多少準備。

撈一下

上一期吊打系列咱們提到了Redis相關的一些知識,還沒看的小夥伴能夠回顧一下 ,這對於這期的閱讀頗有幫助,涉及到主從同步、讀寫分離、持久化這樣的知識點。

打好基礎才能夠寫出更好的代碼喲!否則就等着產品測試懟你吧。

正文

首先設計一個系統以前,咱們須要先確認咱們的業務場景是怎麼樣子的,我就帶着你們一塊兒假設一個場景好吧。

場景

咱們現場要賣100件下面這個嬰兒紙尿褲,而後咱們根據以往這樣秒殺活動的數據經驗來看,目測來搶這100件紙尿褲的人足足有10萬人。(南極人打錢!)

你一聽,完了呀,這咱們的服務器哪裏頂得住啊!說真的直接打DB確定掛。可是別急嘛,有暖男敖丙在,咱們在開始以前應該先思考下會出現哪些問題

問題

高併發:

是的高併發這個是咱們想都不用想的一個點,一瞬間這麼多人進來這不是高併發何時是呢?

是吧,秒殺的特色就是這樣時間極短瞬間用戶量大

正常的店鋪營銷都是用極低的價格配合上短信、APP的精準推送,吸引特別多的用戶來參與這場秒殺,爽了商家苦了開發呀

秒殺你們都知道若是真的營銷到位,價格誘人,幾十萬的流量我以爲徹底不是問題,那單機的Redis我感受3-4W的QPS仍是能頂得住的,可是再高了就沒辦法了,那這個數據隨便搞個熱銷商品的秒殺可能都不止了。

大量的請求進來,咱們須要考慮的點就不少了,緩存雪崩緩存擊穿緩存穿透這些我以前提到的點都是有可能發生的,出現問題打掛DB那就很難受了,活動失敗用戶體驗差,活動人氣沒了,最後背鍋的仍是開發

超賣:

但凡是個秒殺,都怕超賣,我這裏舉例的只是尿不溼,要是換成100個華爲MatePro30,商家的預算經費賣100個能夠賺點還能夠造勢,結果你寫錯程序多賣出去200個,你不發貨用戶投訴你,平臺封你店,你發貨就血虧,你怎麼辦?
(沒事看了敖丙的文章直接不怕)

那最後只能殺個開發祭天解氣了,秒殺的價格原本就低了,基本上都是不怎麼賺錢的,超賣了就恐怖了呀,因此超賣也是很關鍵的一個點。

惡意請求:

你這麼低的價格,假如我搶到了,我轉手賣掉我不是血賺?就算我不賣我也不虧啊,那用戶知道,你知道,別的別有用心的人(黑客、黃牛…)確定也知道的。

那簡單啊,我知道你何時搶,我搞個幾十臺機器搞點腳本,我也模擬出來十幾萬我的左右的請求,那我是否是意味着我基本上有80%的成功率了。

真實狀況可能遠遠不止,由於機器請求的速度比人的手速每每快太多了,在貴州的敖丙我每一年回家搶高鐵票都是秒光的,我也不知道有沒有黃牛的功勞,我要Diss你,黃牛。杰倫演唱會門票搶不到,我也Diss你。

Tip:科普下,小道消息瞭解到的,黃牛的搶票系統,比國內不少小公司的系統還吊不少,架構設計都是頂級的,我用頂配的服務加上頂配的架構設計,你還想看演唱會?還想回家?

不過不用黃牛我回家都難,咱們雲貴川跟我同樣要回家過年的仔太多了555!

連接暴露:

前面幾個問題你們可能都很好理解,一看到這個有的小夥伴可能會比較疑惑,啥是連接暴露呀?

相信是個開發同窗都對這個畫面一點都不陌生吧,懂點行的仔均可以打開谷歌的開發者模式,而後看看你的網頁代碼,有的就有URL,可是我寫VUE的時候是事件觸發而後去調用文件裏面的接口看源碼看不到,可是我能夠點擊一下查看你的請求地址啊,不過你好像能夠對按鈕在秒殺前置灰。

無論怎麼樣子都有危險,撇開外面的全部的東西你都擋住了,你賣這個東西實在便宜得過度,有誘惑力,你能保證開發不動心?開發知道地址,在秒殺的時候本身提早請求。。。(開發:怎麼TM又是我)

數據庫:

每秒上萬甚至十幾萬的QPS(每秒請求數)直接打到數據庫,基本上都要把庫打掛掉,並且你服務不僅僅是作秒殺的還涉及其餘的業務,你沒作降級、限流、熔斷啥的,別的一塊兒掛,小公司的話可能全站崩潰404

反正無論你秒殺怎麼掛,你別把別的搞掛了對吧,搞掛了就不是殺一個程序員能搞定的。

程序員:我TM好難啊!

問題都列出來了,那怎麼設計,怎麼解決這些問題就是接下去要考慮的了,咱們對症下藥。

服務單一職責:

設計個能抗住高併發的系統,我以爲仍是得單一職責

什麼意思呢,你們都知道如今設計都是微服務的設計思想,而後再用分佈式的部署方式

也就是咱們下單是有個訂單服務,用戶登陸管理等有個用戶服務等等,那爲啥咱們不給秒殺也開個服務,咱們把秒殺的代碼業務邏輯放一塊兒。

單獨給他創建一個數據庫,如今的互聯網架構部署都是分庫的,同樣的就是訂單服務對應訂單庫,秒殺咱們也給他創建本身的秒殺庫。

至於表就看你們怎麼設計了,該設置索引的地方仍是要設置索引的,建完後記得用explain看看SQL的執行計劃。(不瞭解的小夥伴也沒事,MySQL章節我會說的)

單一職責的好處就是就算秒殺沒抗住,秒殺庫崩了,服務掛了,也不會影響到其餘的服務。(強行高可用)

秒殺連接加鹽:

咱們上面說了連接要是提早暴露出去可能有人直接訪問url就提早秒殺了,那又有小夥伴要說了我作個時間的校驗就行了呀,那我告訴你,知道連接的地址比起頁面人工點擊的仍是有很大優點

我知道url了,那我經過程序不斷獲取最新的北京時間,能夠達到毫秒級別的,我就在00毫秒的時候請求,我敢說絕對比你人工點的成功率大太多了,並且我能夠一毫秒發送N次請求,搞很差你賣100個產品我全拿了。

那這種狀況怎麼避免?

簡單,把URL動態化,就連寫代碼的人都不知道,你就經過MD5之類的加密算法加密隨機的字符串去作url,而後經過前端代碼獲取url後臺校驗才能經過。

暖男我呢,又準備了一個簡單的url加密給你們嚐嚐鮮,還不點個贊

Redis集羣:

以前不是說單機的Redis頂不住嘛,那簡單多找幾個兄弟啊,秒殺原本就是讀多寫少,那大家是否是瞬間想起來我以前跟大家提到過的,Redis集羣主從同步讀寫分離,咱們還搞點哨兵,開啓持久化直接無敵高可用!

Nginx:

Nginx你們想必都不陌生了吧,這玩意是高性能的web服務器,併發也隨便頂幾萬不是夢,可是咱們的Tomcat只能頂幾百的併發呀,那簡單呀負載均衡嘛,一臺服務幾百,那就多搞點,在秒殺的時候多租點流量機

Tip:據我所知國內某大廠就是在去年春節活動期間租光了亞洲全部的服務器,小公司也很喜歡在雙十一期間買流量機來頂住壓力。

這樣一對比是否是以爲你的集羣能頂不少了。

惡意請求攔截也須要用到它,通常單個用戶請求次數太誇張,不像人爲的請求在網關那一層就得攔截掉了,否則請求多了他搶不搶獲得是一回事,服務器壓力上去了,可能佔用網絡帶寬或者把服務器打崩、緩存擊穿等等。

資源靜態化:

秒殺通常都是特定的商品還有頁面模板,如今通常都是先後端分離的,因此頁面通常都是不會通過後端的,可是前端也要本身的服務器啊,那就把能提早放入cdn服務器的東西都放進去,反正把全部能提高效率的步驟都作一下,減小真正秒殺時候服務器的壓力。

按鈕控制:

你們有沒有發現沒到秒殺前,通常按鈕都是置灰的,只有時間到了,才能點擊。

這是由於怕你們在時間快到的最後幾秒秒瘋狂請求服務器,而後還沒到秒殺的時候基本上服務器就掛了。

這個時候就須要前端的配合,定時去請求你的後端服務器,獲取最新的北京時間,到時間點再給按鈕可用狀態。

按鈕能夠點擊以後也得給他置灰幾秒,否則他同樣在開始以後一直點的。你敢說大家秒殺的時候不是這樣的?

限流:

限流這裏我以爲應該分爲前端限流後端限流

前端限流:這個很簡單,通常秒殺不會讓你一直點的,通常都是點擊一下或者兩下而後幾秒以後才能夠繼續點擊,這也是保護服務器的一種手段。

後端限流:秒殺的時候確定是涉及到後續的訂單生成和支付等操做,可是都只是成功的幸運兒纔會走到那一步,那一旦100個產品賣光了,return了一個false,前端直接秒殺結束,而後你後端也關閉後續無效請求的介入了。

Tip:真正的限流還會有限流組件的加入例如:阿里的Sentinel、Hystrix等。我這裏就不展開了,就說一下物理的限流。

庫存預熱:

秒殺的本質,就是對庫存的搶奪,每一個秒殺的用戶來你都去數據庫查詢庫存校驗庫存,而後扣減庫存,撇開性能因數,你不以爲這樣好繁瑣,對業務開發人員都不友好,並且數據庫頂不住啊。

開發:你tm總算爲我着想一次了。

那怎麼辦?

咱們都知道數據庫頂不住可是他的兄弟非關係型的數據庫Redis能頂啊!

那不簡單了,咱們要開始秒殺前你經過定時任務或者運維同窗提早把商品的庫存加載到Redis中去,讓整個流程都在Redis裏面去作,而後等秒殺介紹了,再異步的去修改庫存就行了。

可是用了Redis就有一個問題了,咱們上面說了咱們採用主從,就是咱們會去讀取庫存而後再判斷而後有庫存纔去減庫存,正常狀況沒問題,可是高併發的狀況問題就很大了。

這裏我就不畫圖了,我原本想畫圖的,想了半天我以爲語言可能更好表達一點。

多品幾遍!!!就好比如今庫存只剩下1個了,咱們高併發嘛,4個服務器一塊兒查詢了發現都是還有1個,那你們都以爲是本身搶到了,就都去扣庫存,那結果就變成了-3,是的只有一個是真的搶到了,別的都是超賣的。咋辦?

Lua:

以前的文章就簡單的提到了他,我今天就多必定點篇幅說一下吧。

Lua 腳本功能是 Reids在 2.6 版本的最大亮點, 經過內嵌對 Lua 環境的支持, Redis 解決了長久以來不能高效地處理 CAS (check-and-set)命令的缺點, 而且能夠經過組合使用多個命令, 輕鬆實現之前很難實現或者不能高效實現的模式。

Lua腳本是相似Redis事務,有必定的原子性,不會被其餘命令插隊,能夠完成一些Redis事務性的操做。這點是關鍵。

知道原理了,咱們就寫一個腳本把判斷庫存扣減庫存的操做都寫在一個腳本丟給Redis去作,那到0了後面的都Return False了是吧,一個失敗了你修改一個開關,直接擋住全部的請求,而後再作後面的事情嘛。

限流&降級&熔斷&隔離:

這個爲啥要作呢,不怕一萬就怕萬一,萬一你真的頂不住了,限流,頂不住就擋一部分出去可是不能說不行,降級,降級了仍是被打掛了,熔斷,至少不要影響別的系統,隔離,你自己就獨立的,可是你會調用其餘的系統嘛,你快不行了你別拖累兄弟們啊。

削峯填谷:

一說到這個名詞,不少小夥伴就知道了,對的MQ,你買東西少了你直接100個請求改庫我以爲沒問題,可是萬一秒殺一萬個,10萬個呢?服務器掛了,程序員又要背鍋的

Tip:可能小夥伴說咱們業務達不到這個量級,不必。可是我想說咱們寫代碼,就不該該寫出有邏輯漏洞的代碼,至少之後公司體量上去了,別人一看竟然不用改代碼,一看代碼做者是敖丙?有點東西!

你能夠把它放消息隊列,而後一點點消費去改庫存就行了嘛,不過單個商品其實一次修改就夠了,我這裏說的是某個點多個商品一塊兒秒殺的場景,像極了雙十一零點。

總結

到這裏我想我已經基本上把該考慮的點還有對應的解決方案也都說了一下,不知道還有沒有沒考慮到的,可是就算沒考慮到我想我這個設計,應該也能撐住一個完整的秒殺流程。

(有大佬的話給敖丙點多的思路,去GitHub https://github.com/JavaFamily 上給我提,也有個人聯繫)

最後我就畫個完整的流程圖給你們收個尾吧!


Tip:這個鏈路仍是比較簡單的,不少細節的點所有畫出來就太複雜了,我上面已經提到了全部的注意點了,你們都看看,真正的秒殺有比我這個簡單的,也有比我這個複雜N倍的,以前的電商老東家就作的很高級,有機會也能夠跟大家探討,不過是面試嘛,我就給思路,讓你理解比較關鍵的點。

秒殺這章我腦細胞死了不少,考慮了不少個點,最後仍是出來了,忍不住給本身點贊

這章是真的不要白嫖,每次都看了不點贊,大家想白嫖我麼?大家好壞喲,不過我好喜歡

總結

咱們玩歸玩,鬧歸鬧,別拿面試開玩笑。

秒殺不必定是每一個同窗都會問到的,至少確定沒Redis基礎那樣常問,可是一旦問到,你們必定要回答到點上。

至少你得說出可能出現的狀況須要注意的狀況,以及對於的解決思路和方案

最後就是須要對整個鏈路比較熟悉,注意是一個完整的鏈路,前端怎麼設計的呀,網關的做用呀,怎麼解決Redis的併發競爭啊,數據的同步方式呀,MQ的做用啊。

(提到MQ又是一整條的知識鏈路,什麼異步、削峯、解耦等等,因此面試,咱們仍是不打沒有把握的勝仗)

流着淚說再見

Redis系列到此是真的要跟你們說再見了,寫了7篇文章,其實不少大佬的思路和片斷真心贊,其實你們看出來了個人文章我的風格色彩特別濃厚,我我的在生活中就是這麼說話的,也但願用這種風格把本來枯燥乏味的知識點讓你們都像看小說同樣津津有味的看下去,不知道你們什麼感覺,好的很差的都請給我留言。

我這個系列的我會寫到我GitHub https://github.com/JavaFamily 圖中全部的知識點,之後就麻煩你們多多關照了,我寫做的時間都是業餘時間,基本上週末和晚上的時間都貢獻出來了,我也是個新人不少點也沒接觸到,也要看書看資料才能寫出來,因此有時候仍是但願你們多多包涵。

那咱們下期見!

下期寫____

不告訴你,哈哈!

平常求贊

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才

我後面會每週都更新幾篇《吊打面試官》系列和互聯網經常使用技術棧相關的文章,很是感謝人才們能看到這裏,若是這個文章寫得還不錯,以爲「敖丙」我有點東西的話 求點贊👍 求關注❤️ 求分享👥 對暖男我來講真的 很是有用!!!

創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!

敖丙 | 文 【原創】【轉載請聯繫本人】 若是本篇博客有任何錯誤,請批評指教,不勝感激 !


《吊打面試官》系列每週持續更新,能夠關注個人公衆號「JavaFamily」第一時間閱讀和催更(公衆號比博客早一到兩篇喲),本文GitHub上已經收錄https://github.com/JavaFamily,有一線大廠面試點思惟導圖,歡迎Star和完善,裏面也有我我的聯繫方式有什麼問題也能夠直接找我,也有人才交流羣,咱們一塊兒有點東西。

相關文章
相關標籤/搜索