秒殺系統我的總結

秒殺系統架構

秒殺系統是一個併發量要求高、負載均衡要求高的、業務場景簡單可是邏輯稍微複雜的系統,因此常常會做爲面試高級後端開發的面試題。主要考察的就是對問題的拆解、分析、解決,以及架構設計的能力。前端

基礎架構

  • 客戶端
    • web 瀏覽器 / app
  • 負載均衡層
    • Nginx
  • web 層
    • 接收 Http 請求
    • 作限流
      • 分佈式限流
      • id 限流
  • service 層
    • 庫存操做
    • 生成訂單
  • 數據存儲層
    • mq + mysql

客戶端

服務端是一個潛在的考察點,仍是有不少問題須要解決的。有些網上給出的設計方案沒有對這塊作詳細考慮。mysql

  • 客戶端限流(在瀏覽器上行不通)web

    客戶端作必定控制來限流(好比機率),防止刷單,減小成功次數,顯示在排隊,實際上沒髮網絡請求面試

  • 前端展現redis

    秒殺按鈕展現要有個定時器,涉及到先後端時鐘同步的問題sql

    • 校對時間差後端

      獲取服務端時間,客戶端時間 - 服務端時間,比較獲得差值,用這種方法來同步。然而注意到網絡是有開銷的,這個開銷須要想辦法消除。不然這種毫秒級甚至秒級的時間差,會影響到秒殺的公平性。瀏覽器

      • 發送更輕量級的服務響應
      • 優化代碼,使客戶端和服務端計算時間的流程很短
      • 回調計算時間先執行

      若是這個同步是很長時間以前同步的呢,可能時間過了好久後已經相差較多了。緩存

      • 定時同步,半小時一次

      若是客戶修改系統時間怎麼辦服務器

      • 記錄客戶端的週期時間序列(這個週期能夠設置的短一些,好比10秒這樣子),第一次爲基準,先作客戶端與服務端同步,獲得差值 T
      • 在第二個週期,計算兩個時刻的時間差,再減去週期時間,就是相差的時間,若是在某一個很小的範圍內,說明沒有問題,若是不在範圍內,說明可能修改了時間,那麼修改 T 爲 T + 差值

web 層

這一層要考慮限流問題,以及防止惡意刷量的問題。首先限流要儘可能在上層去作,以最大程度減小後端系統的壓力。其次,要避免用戶找到url,不停的大量發送網絡請求,或者在活動前就發送,這樣也是有問題的。

  • 限流

    這屬於分佈式限流,通常採用 redis 來作限流,能夠用令牌桶來作

  • 防止提早刷 url

    這個能夠在服務端根據系統時間來決定要不要處理,也能夠用一個隨機的網址來保證沒法模擬 url 請求(這個點還比較模糊)
    並且這裏涉及到服務端各服務器的時鐘同步

  • 同一個 url

    這裏能夠用 redis 記錄或者本地記錄來進行計數過濾,保證用戶每秒發送請求響應次數不超過一個閾值

service 層

  • 若是有庫存,而且拿到了資源,再生單的邏輯順序
  • 解決併發問題的思路
      • 悲觀鎖

        性能比較差

      • 樂觀錯

        性能好些

    • 緩存

      緩存來保存庫存量,減小訪問 mysql 帶來的併發,用 redis 能夠作到

      可是若是在拿到資格後出現問題,怎麼辦?在緩存裏已經被減掉了,這時須要歸還資格,不然賣出的數就會少,這個錯誤可能會出如今生單,訂單入庫的階段,直到入庫,這個資格才能算做完全被消費掉

數據存儲層

mysql 更合適,有惟一鍵的限制,hbase 存放海量數據

同步仍是異步的問題

  • 同步

    好處,等待結果寫入庫裏,徹底閉環

  • 異步

    可能會寫入失敗,丟失訂單信息,由於訂單詳情是要儘快展現給用戶的,因此一旦失敗,該取消此次秒殺的結果,仍是繼續認爲成功,是比較棘手的問題。異步出錯了,可能能夠修復,可是也可能會一直出錯,重試無效。這種應該歸還,而後把結果通知給用戶。若是異步默認生單成功,可是怎麼也寫不進去,那就會有問題了。(這塊每太想清楚)

    先說說異步作法

    • 交由本地線程池處理

      佔用 service 層資源

    • 發送 kafka

      減小了 service 層資源佔用,可是要保證 kafka 可靠,這裏須要保證 有副本,ack -> ALL,replica 設置>1

其餘問題

  • 如何保證同一個用戶只能下一個單

    • 若是是用 redis 來作
      • 那麼能夠在獲取權限的前一層寫入,作第一層判斷
      • 也就是若是獲取到一次資格,立馬鎖定,若是後面的生單失敗了,再解鎖
    • 若是用 mysql 來作
      • 會致使在最下層才判斷出來,而前面已經拿到了資格,致使不少人沒搶到,這時應該返回什麼?通常返回失敗,直到全局的秒殺結束,再通知結束。
  • 由於資源被佔用後,後續不必定生單成功,因此若是資源沒了,不該該直接展現秒殺結束

    • 要有一個全局的標識,確認秒殺結束
  • server 端時間同步

    • 服務啓動時以某一個爲基準就好,能夠是集羣中的,也能夠是集羣外的
相關文章
相關標籤/搜索