1. 程式人生 > >秒殺系統優化思路

秒殺系統優化思路

按鈕 clas 繼續 -i 火車票 時間 有意 用戶 頁面

一、秒殺業務為什麽這麽難做

秒殺系統,庫存只有一份,所有人會在集中的時間讀和寫這些數據。

例如:

  • 小米手機每周二的秒殺,可能手機只有1萬部,但瞬間進入的流量可能是幾百幾千萬。
  • 12306搶票,票是有限的,但是搶票的人很多,都讀取相同的庫存。讀寫沖突,鎖非常嚴重,這是業務難的地方。

那我們怎麽優化秒殺業務呢?

二、優化方向

(以上的兩個場景要優化有兩個方向)

  • 將請求盡量攔截在系統上遊(不要讓鎖沖突落到數據庫上去)。傳統的秒殺系統之所以掛,是因為請求都壓到後端數據層,數據讀寫沖突嚴重,並發高響應慢,幾乎所有請求都超時,流量最大,下單成功的有效流量非常小。以12306為例,一趟火車其實只有2000張票,但是搶到的人卻有200萬,基本沒人能買票成功,請求有效率為0.
  • 充分利用緩存,秒殺買票,這是一個典型的讀多寫少的應用場景,大部分請求是車次/票查詢,下單和支付才是寫請求。一趟火車只有2000張票,200萬人來買,最多2000人下單成功,其他人都是查庫存,寫入操作的比例是0.1%,而讀取的操作比例是99.9%,非常適合緩存來做優化。

三、常見秒殺架構

常見的秒殺架構基本是這樣的

技術分享圖片

  • 瀏覽器端,最上層,會執行一些JS代碼
  • 站點層,這一層會訪問後端數據,將操作響應返回給瀏覽器
  • 服務層,向上遊屏蔽底層數據細節,提供數據訪問
  • 數據層,最終的“庫存”會存放在這裏,mysql是一個典型(當然還有緩存),這張圖雖然簡單,但是能形象的說明大流量高並發的秒殺業務架構(根據筆者從業的經驗,基本所有公司的軟件架構都脫離不了這幾層,大同小異),後面詳細解  析各層級怎麽優化。

四、各層優化細節

  • 第一層:客戶端怎麽優化(瀏覽器層,APP層)

    大家應該都玩過微信搖一搖搶紅包,是每一次搖一搖,就會往後端發送請求麽?

    回顧一下我們12306剛出來那年搶票的場景,點擊“查詢”按鈕之後,系統卡在那裏或者響應非常慢,這時用戶就會再次點擊”查詢“,繼續點點點,可是這樣有用麽?徙增系統負載,如果真實購買用戶只有200W,那一個用戶多點擊5次,

    就有1000萬,多出來80%的用戶怎麽整?

    • 產品層面優化:用戶點擊查詢或者購票操作後,按鈕置灰,禁止用戶重復提交。
    • JS層面優化:限制用戶在x秒內只能提交一次請求。

    上面說到搖紅包,就算我們瘋狂的把手機甩飛了,系統也只是在x秒才向系統發送請求。

    這就是所謂的“將請求盡量攔截在系統上遊”,越上遊越好,瀏覽器層,APP層就給攔住,這樣就擋住了多出那80%的用戶請求。

    但是,這種辦法只能攔截住普通的用戶,對於高端的程序猿們來說是攔不住的,firebug一抓包,http長啥樣都知道了,js是攔不住程序員寫for循環調用http接口的,這部分請求如何處理?

  • 第二層:站點層面的請求攔截

    怎麽防止程序猿們for循環請求呢?有去重依據麽?ip?cookie-id?這類“秒殺”業務都需要登錄,用我們加了密的uid即可。在站點層面,對uid進行請求計數和去重,一個uid在5秒內只允許1個請求(例如生成uid時加入時間戳),

    這樣就可以攔截住程序猿們的for循環請求。

    5秒只透過一個請求,那其他請求怎麽辦?緩存,頁面緩存,同一個uid訪問頻度做頁面緩存,x秒內到達站點請求,均返回同一個頁面。 如此限流,既能保證用戶體驗又能保證系統的健壯性。

    (頁面緩存不一定要保證所有站點返回一致的頁面,直接放在每個站點的內存也可以,優點是簡單。缺點是http請求落到不同的站點,返回的車票數據可能不一樣。)

    這是站點層請求攔截和緩存的優化

    如果,有黑客控制了10萬個肉雞,不同的uid,同時發送請求的話,我們怎麽辦?站點層按照uid限流已經攔截不住了。

  • 第三層:服務層攔截

  (反正不要讓請求落到數據層上)

    服務層如何來攔截呢?請求隊列,對於寫入操作的請求,每次只透有限的請求去數據層,這個有限取決於有多少部小米手機或多少張火車票。如果庫存不夠則全部返回“已售完”。

    對於讀取的請求如何優化?用cache抗 ,不管是mecached還是redis,單機抗個每秒10萬都沒問題,如此限流,只有非常少的寫入請求,和非常少的讀取緩存mis的請求會透到數據層去,又有99.9%的請求被攔住了。

  • 第四層:數據層

    瀏覽器攔截了80%,站點層攔截了99.9%並做了頁面緩存,服務層又做了請求隊列與數據緩存,每次透到數據層的請求都是可控的。db基本沒什麽壓力了,還是那句話,庫存是有限的,透這麽多請求來數據庫沒有意義。

    全部透到數據庫,100萬個下單,0個成功,透3000到數據庫,全部成功。請求有效率為100%。

總結:

  再重復一下關於秒殺系統的兩個優化思路:

  • 盡量將請求攔截在系統上遊(越上遊越好)
  • 讀多寫少的應用多使用緩存(緩存抗讀壓力)
  • 瀏覽器和APP:做限速
  • 站點層:按照uid限速,做頁面緩存
  • 服務器:按照業務做寫請求隊列控制流量,做數據緩存
  • 數據層:閑庭信步
  • 並且結合業務做優化。

文章內容來源於微信公眾號“架構師之路”,歡迎大家關註。

我在文章中看到了幾個技術點:memcache請求隊列。有時間我好好研究一下,再整理到自己的博客上。

如果大家有什麽好的想法,可以留言,我肯定會學習並實踐好再拿出來分享。

非常感謝。

如果對您有幫助,請點贊!

秒殺系統優化思路