【分布式技術專題】「架構設計方案」盤點和總結秒殺服務的功能設計及注意事項技術體系

秒殺應該考慮哪些問題

超賣問題

分析秒殺的業(yè)務場景激率,最重要的有一點就是超賣問題,假如備貨只有100個勿决,但是最終超賣了200乒躺,一般來講秒殺系統(tǒng)的價格都比較低,如果超賣將嚴重影響公司的財產(chǎn)利益低缩,因此首當其沖的就是解決商品的超賣問題嘉冒。

高并發(fā)

秒殺具有時間短、并發(fā)量大的特點咆繁,秒殺持續(xù)時間只有幾分鐘讳推,而一般公司都為了制造轟動效應,會以極低的價格來吸引用戶玩般,因此參與搶購的用戶會非常的多银觅。短時間內(nèi)會有大量請求涌進來,后端如何防止并發(fā)過高造成緩存擊穿或者失效坏为,擊垮數(shù)據(jù)庫都是需要考慮的問題究驴。

接口防刷

現(xiàn)在的秒殺大多都會出來針對秒殺對應的軟件慨仿,這類軟件會模擬不斷向后臺服務器發(fā)起請求,一秒幾百次都是很常見的纳胧,如何防止這類軟件的重復無效請求镰吆,防止不斷發(fā)起的請求也是需要我們針對性考慮的

秒殺url

對于普通用戶來講,看到的只是一個比較簡單的秒殺頁面跑慕,在未達到規(guī)定時間万皿,秒殺按鈕是灰色的,一旦到達規(guī)定時間核行,灰色按鈕變成可點擊狀態(tài)牢硅。這部分是針對小白用戶的,如果是稍微有點電腦功底的用戶芝雪,會通過F12看瀏覽器的network看到秒殺的url减余,通過特定軟件去請求也可以實現(xiàn)秒殺〕拖担或者提前知道秒殺url的人位岔,一請求就直接實現(xiàn)秒殺了。這個問題我們需要考慮解決

數(shù)據(jù)庫設計

秒殺有把我們服務器擊垮的風險堡牡,如果讓它與我們的其他業(yè)務使用在同一個數(shù)據(jù)庫中抒抬,耦合在一起,就很有可能牽連和影響其他的業(yè)務晤柄。如何防止這類問題發(fā)生擦剑,就算秒殺發(fā)生了宕機、服務器卡死問題芥颈,也應該讓他盡量不影響線上正常進行的業(yè)務

大量請求問題

按照1.2的考慮惠勒,就算使用緩存還是不足以應對短時間的高并發(fā)的流量的沖擊。如何承載這樣巨大的訪問量爬坑,同時提供穩(wěn)定低時延的服務保證纠屋,是需要面對的一大挑戰(zhàn)。我們來算一筆賬妇垢,假如使用的是redis緩存巾遭,單臺redis服務器可承受的QPS大概是4W左右肉康,如果一個秒殺吸引的用戶量足夠多的話闯估,單QPS可能達到幾十萬,單體redis還是不足以支撐如此巨大的請求量吼和。緩存會被擊穿涨薪,直接滲透到DB,從而擊垮mysql.后臺會將會大量報錯

秒殺系統(tǒng)的設計和技術方案

秒殺系統(tǒng)數(shù)據(jù)庫設計

針對提出的秒殺數(shù)據(jù)庫的問題,因此應該單獨設計一個秒殺數(shù)據(jù)庫炫乓,防止因為秒殺活動的高并發(fā)訪問拖垮整個網(wǎng)站刚夺。這里只需要兩張表献丑,一張是秒殺訂單表

秒殺系統(tǒng)數(shù)據(jù)庫設計

其實應該還有幾張表,商品表:可以關聯(lián)goods_id查到具體的商品信息侠姑,商品圖像创橄、名稱、平時價格莽红、秒殺價格等妥畏,還有用戶表:根據(jù)用戶user_id可以查詢到用戶昵稱、用戶手機號安吁,收貨地址等其他額外信息醉蚁,這個具體就不給出實例了。

秒殺url的設計

為了避免有程序訪問經(jīng)驗的人通過下單頁面url直接訪問后臺接口來秒殺貨品鬼店,我們需要將秒殺的url實現(xiàn)動態(tài)化网棍,即使是開發(fā)整個系統(tǒng)的人都無法在秒殺開始前知道秒殺的url。

具體的做法就是通過md5加密一串隨機字符作為秒殺的url妇智,然后前端訪問后臺獲取具體的url滥玷,后臺校驗通過之后才可以繼續(xù)秒殺。

秒殺頁面靜態(tài)化

將商品的描述巍棱、參數(shù)罗捎、成交記錄、圖像拉盾、評價等全部寫入到一個靜態(tài)頁面桨菜,用戶請求不需要通過訪問后端服務器,不需要經(jīng)過數(shù)據(jù)庫捉偏,直接在前臺客戶端生成倒得,這樣可以最大可能的減少服務器的壓力。

具體的方法可以使用freemarker模板技術夭禽,建立網(wǎng)頁模板霞掺,填充數(shù)據(jù),然后渲染網(wǎng)頁

單體redis升級為集群redis

秒殺是一個讀多寫少的場景讹躯,使用redis做緩存再合適不過菩彬。不過考慮到緩存擊穿問題,我們應該構建redis集群潮梯,采用哨兵模式骗灶,可以提升redis的性能和可用性。

使用nginx

nginx是一個高性能web服務器秉馏,它的并發(fā)能力可以達到幾萬耙旦,而tomcat只有幾百。通過nginx映射客戶端請求萝究,再分發(fā)到后臺tomcat服務器集群中可以提升并發(fā)能力免都。

精簡sql

典型的一個場景是在進行扣減庫存的時候锉罐,傳統(tǒng)的做法是先查詢庫存,再去update绕娘。這樣的話需要兩個sql脓规,而實際上一個sql我們就可以完成的。

可以用這樣的做法:update miaosha_goods set stock =stock-1 where goos_id ={#goods_id} and version = #{version} and sock>0;這樣的話险领,就可以保證庫存不會超賣并且一次更新庫存,還有注意一點這里使用了版本號的樂觀鎖抖拦,相比較悲觀鎖,它的性能較好舷暮。

redis預減庫存

很多請求進來态罪,都需要后臺查詢庫存,這是一個頻繁讀的場景∠旅妫可以使用redis來預減庫存复颈,在秒殺開始前可以在redis設值,比如redis.set(goodsId,100),這里預放的庫存為100可以設值為常量),每次下單成功之后,Integer stock = (Integer)redis.get(goosId); 然后判斷sock的值沥割,如果小于常量值就減去1;

不過注意當取消的時候,需要增加庫存耗啦,增加庫存的時候也得注意不能大于之間設定的總庫存數(shù)(查詢庫存和扣減庫存需要原子操作,此時可以借助lua腳本)下次下單再獲取庫存的時候,直接從redis里面查就可以了机杜。

接口限流

秒殺最終的本質(zhì)是數(shù)據(jù)庫的更新帜讲,但是有很多大量無效的請求,我們最終要做的就是如何把這些無效的請求過濾掉椒拗,防止?jié)B透到數(shù)據(jù)庫似将。限流的話,需要入手的方面很多:

前端限流

首先第一步就是通過前端限流蚀苛,用戶在秒殺按鈕點擊以后發(fā)起請求在验,那么在接下來的5秒是無法點擊(通過設置按鈕為disable)。這一小舉措開發(fā)起來成本很小堵未,但是很有效腋舌。

同一個用戶xx秒內(nèi)重復請求直接拒絕

具體多少秒需要根據(jù)實際業(yè)務和秒殺的人數(shù)而定,一般限定為10秒渗蟹。具體的做法就是通過redis的鍵過期策略块饺,首先對每個請求都從String value = redis.get(userId);如果獲取到這個

value為空或者為null,表示它是有效的請求雌芽,然后放行這個請求授艰。如果不為空表示它是重復性請求,直接丟掉這個請求膘怕。如果有效,采用redis.setexpire(userId,value,10).value可以是任意值想诅,一般放業(yè)務屬性比較好,這個是設置以userId為key,10秒的過期時間(10秒后,key對應的值自動為null)

令牌桶算法限流

接口限流的策略有很多岛心,我們這里采用令牌桶算法来破。令牌桶算法的基本思路是每個請求嘗試獲取一個令牌,后端只處理持有令牌的請求忘古,生產(chǎn)令牌的速度和效率我們都可以自己限定徘禁,guava提供了RateLimter的api供我們使用。

異步下單

為了提升下單的效率髓堪,并且防止下單服務的失敗送朱。需要將下單這一操作進行異步處理。最常采用的辦法是使用隊列干旁,隊列最顯著的三個優(yōu)點:異步驶沼、削峰、解耦争群。這里可以采用rabbitmq回怜,在后臺經(jīng)過了限流、庫存校驗之后换薄,流入到這一步驟的就是有效請求玉雾。然后發(fā)送到隊列里,隊列接受消息轻要,異步下單复旬。下完單,入庫沒有問題可以用短信通知用戶秒殺成功冲泥。假如失敗的話,可以采用補償機制驹碍,重試。

服務降級

假如在秒殺過程中出現(xiàn)了某個服務器宕機凡恍,或者服務不可用幸冻,應該做好后備工作。之前的博客里有介紹通過Hystrix進行服務熔斷和降級咳焚,可以開發(fā)一個備用服務洽损,假如服務器真的宕機了,直接給用戶一個友好的提示返回革半,而不是直接卡死碑定,服務器錯誤等生硬的反饋。

image

這就是我設計出來的秒殺流程圖,當然不同的秒殺體量針對的技術選型都不一樣又官,這個流程可以支撐起幾十萬的流量延刘,如果是成千萬破億那就得重新設計了。比如數(shù)據(jù)庫的分庫分表六敬、隊列改成用kafka碘赖、redis增加集群數(shù)量等手段。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市普泡,隨后出現(xiàn)的幾起案子播掷,更是在濱河造成了極大的恐慌,老刑警劉巖撼班,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件歧匈,死亡現(xiàn)場離奇詭異,居然都是意外死亡砰嘁,警方通過查閱死者的電腦和手機件炉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矮湘,“玉大人斟冕,你說我怎么就攤上這事∶逖簦” “怎么了磕蛇?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長券时。 經(jīng)常有香客問我孤里,道長,這世上最難降的妖魔是什么橘洞? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任捌袜,我火速辦了婚禮,結果婚禮上炸枣,老公的妹妹穿的比我還像新娘虏等。我一直安慰自己,他們只是感情好适肠,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布霍衫。 她就那樣靜靜地躺著,像睡著了一般侯养。 火紅的嫁衣襯著肌膚如雪敦跌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天逛揩,我揣著相機與錄音柠傍,去河邊找鬼。 笑死辩稽,一個胖子當著我的面吹牛惧笛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逞泄,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼患整,長吁一口氣:“原來是場噩夢啊……” “哼拜效!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起各谚,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤紧憾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嘲碧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稻励,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡父阻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年愈涩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片加矛。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡履婉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出斟览,到底是詐尸還是另有隱情毁腿,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布苛茂,位于F島的核電站已烤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妓羊。R本人自食惡果不足惜胯究,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躁绸。 院中可真熱鬧裕循,春花似錦、人聲如沸净刮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淹父。三九已至株婴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暑认,已是汗流浹背困介。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穷吮,地道東北人逻翁。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像捡鱼,于是被迫代替她去往敵國和親八回。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容