我是一個秒殺請求,正在逃離這顆星球...
作者 | 悟空哥
來源 | 悟空聊架構(ID:PassJava666)
星球簡介
地點:β-410 星系,A-731電商星球。
時間:新紀元 2036 年。
星球簡介:
- 中文名:A-731電商星球
- 外文名:A-731 Mall
- 分類:行星
- 公轉周期:一年
- 常駐用戶:中間件工作者、各種請求。
- 星球總歷史:二十萬年。
星球危機
我是一個秒殺請求,每天的工作就是將秒殺請求的數據運送給后端工作者。
這天我在 Nginx 轉發服務器上遇見了請求「小空」 ,我跟小空說有重要消息不方便現在告訴他,下班再約,然后就都匆匆趕路了。
我和小空晚上十點下班后來到一家酒吧,點了兩杯 mojito,找了一個角落坐下。
小空:你最近看起來心事重重。
我:你有沒有發現最近我們星球的訂單數急劇增加,每天有一千萬訂單數據產生,也不是一天、兩天的事了。
小空:難怪我每天加班到晚上十點來運送請求數據。
我:我有個舅舅在航天局上班,告訴我說我們星球承載不了那么多請求和訂單數據,不久就會出現「行星大爆炸」 。你可不要透露給別人。
小空:那怎么辦?
我:我們可以去 100 光年外的 T-714 星球,但是只能通過秒殺通道坐時空穿梭機去那顆星球。而且名額有限制,不知道我有沒有機會登上穿梭機。
我:明天通道會開啟兩次,上午十點和下午兩點。你明天和我一起去吧!
小空:好的。
星球大爆炸
「涉及的知識點:」
- 這里的行星大爆炸指的是什么?
- 因訂單數據量很大,數據庫撐不住了。數據庫可能宕機。
- 因每天有大量請求發送到服務器,服務器也扛不住了。服務器可能宕機。
- 秒殺通道每天開啟兩次代表了什么?
- 「流量錯峰」 ,將流量分攤到兩個秒殺場次。
- 當然「流量錯峰」 的手段還有輸入驗證、加入購物車等分攤流量的做法。
秒殺通道
地點:A-731 星球機場
時間:09 : 45
通道
“請前往 T-714 星球的請求旅客到 Y1 站臺排隊等待進入特殊通道, 15 分鐘后開始進入穿梭機大廳”。大廳的廣播連續播放了三遍。
我走向了特殊通道,看到通道旁立著一個牌子:秒殺通道,只給秒殺請求使用。
「涉及知識點:」
- 秒殺場景為什么單獨弄了條通道?
- 秒殺業務為了不影響系統的其他業務單獨部署了一套秒殺系統。
- 總結為「服務單一職責 + 獨立部署」
實時大屏
一抬頭看到通道上方有一個大屏,在不斷播放 T-714 星球的照片,以及機票的訂單信息。
T-714 星球
有兩個穿制服的工作者正在大屏旁巡邏。一個制服上印著 Nginx,一個制服上印著 CDN。
Nginx+CDN
「涉及知識點:」
- Nginx 制服:
- 穿 Nginx 制服的工作者在維護 Nginx 的靜態和動態資源。
- 商品詳情頁是一個靜態頁面,將這些靜態頁面存儲到 Nginx 服務器上,訪問靜態資源時,請求先到 Nginx,然后 Nginx 服務器通過請求的 URL 鏈接來匹配是否是訪問的靜態資源。
- 大屏的商品詳情頁并不是通過發送請求從后臺服務器拿到的。其實實現了「動靜分離」 。
- 一張圖解釋 Nginx 動靜分離
Nginx 流程圖
- 靜態資源比如 HTML 文件極少變化,就可以專門放到一臺服務器上,直接訪問,不需要與后臺服務器交互(比如 Tomcat)。
- 動態資源比如需要從后臺拿到有多少人購買了商品,發送下單請求來存儲數據,這些都稱作動態資源,不能狹隘的理解為看得見的資源,廣義上可以包括獲取邏輯處理的結果,執行存儲數據等操作。
- CDN 制服
- 什么是 CDN:CDN 大白話解釋就是用戶就近獲取資源,減少網絡傳輸時間,提高訪問速度。
- Nginx 上放 HTML文件,而 CDN 上則放 HTML 引入的圖片文件、腳本文件。
- 穿 CDN 制服的工作者在維護 CDN 的資源。
- 一張流程圖解釋 CDN 工作原理
CDN 流程圖
驗證通道
時間:10:00
“驗證通道已開啟,請攜帶密碼進入!” 又是播放了三遍廣播。
輸入密碼
「涉及的知識點:」
- 為什么需要密碼?
- 為了防止大量模擬的秒殺請求進入業務處理流程,所以先加一道驗證,丟棄這些假請求。
- 怎么做到的?前端網頁先發送請求拿到密碼,點擊搶購時,請求體中攜帶加密密碼,后端校驗密碼是否匹配??梢酝ㄟ^ MD5 加密。
- 總結為「秒殺請求加密」 。
穿梭機大廳
穿梭機大廳
經過驗證通道的篩選后,有一半的假請求被擋在門外,像我這種拿到了正確密碼的順利進入了穿梭機大廳。
來到大廳,發現大廳的正中央擺放著一個顯示器,上面顯示的紅色數字 100 赫然映入眼中。
顯示屏的左手邊站著一位穿著 Redis 統一制服的靚女。在一旁的我偷聽到原來她是控制顯示器顯示穿梭機剩余數量的。如果數字變為 0 ,則表示穿梭機已經全部被占用,后來的人就得無功而返了。
「涉及的知識點:」
- 秒殺場景中,查詢剩余庫存并不是直接查數據庫,而是查 Redis 緩存的。
- 為什么是查緩存?因為查緩存的速度要遠遠快于查數據庫,減少了響應時間,而且對數據庫的壓力減小了很多。如果很多查庫存的請求都到數據庫了,那數據庫就要崩了,而且數據庫干不了其他的活了。
搶票
顯示屏的右手邊站著一位西裝筆挺的年輕帥哥,看到他的袖口上掛著一個紅袖章,印著 Redisson 字樣。他一臉嚴肅的模樣,對大廳內黑壓壓一片的請求熟視無睹。可能是見慣了這種場景吧。
正在打量這位帥哥時,發現他的左手拿著一疊機票,沒錯,有了一張機票就可以登入穿梭機了。我以百米沖速的速度到達了他面前,到達他面前時,已經有十幾個請求也到了他身邊,他按照先來后到的順序依次發放機票,到我的時候,機票已經只剩幾張了,慶幸的是我的百米沖速幫我搶到了一張機票。我問帥哥是否可以再發一張票給我,他拒絕了。
每一次發放票,穿 Redis 制服的靚女都會操作顯示屏,讓其數量減一。
十秒鐘后,票已經發完,顯示屏顯示數字 0 。
「涉及的知識點:」
- Redisson 是啥呢?Redis 客戶端,解決了分布式的一些常見問題。
- 這里其實用到了 Redisson 的信號量功能,總共有 100 張票,也就是 100 個信號量,而且票的數量不會因為多線程并發或分布式系統的原因而導致票的數量被超賣。比如賣出了 101 張票。
- 每個人只能獲得一張票,這就是秒殺系統中涉及到的冪等性校驗,不能重復搶票。
售票窗口
登機牌
登機牌
發放機票的帥哥告訴我,拿到票后,到 A 窗口排隊付款,才能拿到登記牌。于是我和另外 99 個請求一起在 A 窗口排隊了。
看到一個請求想要放棄付款了,說是機票太貴了,然后準備離開大廳時,被發放機票的帥哥攔住了,他問請求是否要考慮下,有 15 分鐘的考慮時間,如果請求還是覺得不行,可以將機票還給他,他可以再發放給其他人。
隊列削峰
「涉及的知識點:」
- 秒殺系統中常用的「隊列削峰」 。秒殺成功的請求,進入隊列,慢慢創建訂單、扣減庫存。
- 秒殺成功后,快速告訴用戶已經秒殺成功,而不是等待訂單完再告訴用戶,那用戶就要多等一會了,影響體驗。
- 為什么要做隊列削峰?成功的請求不必一下子都去數據庫創建訂單,這樣對數據庫的壓力也會小一些。
- 在秒殺場景中,很有可能有用戶搶到了但是不付款的場景,這個時候庫存是要加回去的,可以提供給其他用戶。
啟航
訂單創建成功后,我順利拿到了登機牌,通過了登機牌的校驗后,成功登上了穿梭機。
出發,去往 T-714 星球。聽說那個星球的數據庫進行了分庫分表、服務也拆分成了微服務。
總結
上面通過科幻小說的方式來講解了秒殺系統中關注的點,下面是對秒殺系統關注的八大點的一個總結:
秒殺場景關注點
- 服務單一職責、獨立部署
- 庫存預熱、快速扣減
- 秒殺鏈接加密
- 動靜分離
- 惡意請求攔截
- 流量錯峰
- 限流&熔斷&降級
- 隊列削峰
本文轉載自微信公眾號「悟空聊架構」,可以通過以下二維碼關注。轉載本文請聯系悟空聊架構公眾號。