輕鬆搞定高併發秒殺

1、背景

  • 秒殺通常都是定時上架的 不少人搶 不停的刷新 
  • 瞬間流量暴漲  商品瞬間賣完 要擔憂超賣問題
  • 查詢商品->建立訂單->扣減庫存->更新訂單->付款->賣家發貨   大部分過程短期完成

2、隔離

2.1 業務隔離

        秒殺活動只是網站營銷的一個附加活動,這個活動具備時間短,併發訪問量大的特色,若是和網站原有應用部署在一塊兒,必然會對現有業務形成衝擊,稍有不慎可能致使整個網站癱瘓。css

  • 獨立部署 (集羣隔離)
  • 域名隔離

2.2 數據隔離

        秒殺大部分使用的都是熱數據,能夠啓用單獨的cache集羣 和 mysql 集羣  數據還須要預熱 提早用程序寫到緩存裏面mysql

2.3 動靜隔離

  • 靜態資源都放在CDN上 
  • 把整個頁面Cache在用戶瀏覽器 強制刷新整個頁面,再請求到CDN (這樣把90%的靜態數據緩存在用戶端或者CDN上,當真正秒殺時用戶只須要點擊特殊的按鈕「刷新搶寶」便可,而不須要刷新整個頁面)
  • 只有動態請求才能打到服務器上

 

3、多級緩存

3.1 瀏覽器緩存

靜態頁面直接緩存到瀏覽器中nginx

3.2 CDN緩存

靜態資源放到CDN上  並申請擴大CDN帶寬web

3.3 nginx緩存

靜態資源也能夠緩存到nginx上redis

3.4 本地緩存

不用動態更新的商品信息 , 配置數據能夠提早緩存到web服務內存中sql

3.5 Redis分佈式緩存 

商品庫存, 商品信息 ,用戶信息 等能夠放到redis裏面。數據庫

4、流量削峯

4.1 基於時間分片削峯

        秒殺的流量走勢在秒殺開始的時候會瞬間達到峯值 一柱擎天,對系統的壓力很大 , 能夠在點擊秒殺的時候 加入驗證碼 答題等方式 強行平滑一波曲線。瀏覽器

4.2 基於隊列削峯

      能夠吧請求放入到kafka等隊列中,使用消費者控制消費速度。緩存

5、限流熔斷

5.1 Nginx 限流

  • 能夠針對IP進行漏桶限流 容許必定程度的併發
  • 能夠針對IP進行鏈接數的限流

5.2  Hystrix 限流

  • 須要對下游的服務進行限流 不然可能會形成服務雪崩
  • 對限流的流量能夠直接作未秒殺成功的處理 反正他們也不知道

6、防止超賣

         秒殺流量異常巨大,用數據庫扣減庫存(不管樂觀鎖、悲觀鎖) , 悲觀鎖會形成大量的事務阻塞在mysql,可能會致使整個系統不響應。樂觀鎖想須要獲取一下版本號,而後大併發的更新同一行。雖然mysql 企業版提供了線程池排隊插件(要錢的),可是依然沒法知足好幾萬QPS的要求。tomcat

       比較好的方法  庫存保存在redis中,使用redis lua 腳本 + kafka落地mysql 。 

       爲何要用redis + lua ?

       redis 速度快,lua 實現原子性。  下面代碼不具有原子性。

int 庫存 = redis.get(key);
if(庫存 > 0){
  redis.decr(key)
}

    redis 須要開啓AOF持久化 ,可是畢竟是異步複製,因此仍是須要經過kafka 落地到mysql 裏面的。

若是lua 腳本返回0  , 標識秒殺結束 , 修改內存中的標誌位。 後續請求所有做廢。

7、 優化

7.1 web容器優化

    tomcat jetty 其實不太適合瞬時高併發應用, 可使用undertow 基於NIO實現 吞吐量更高。

7.2 nginx 優化

   連接數 , 線程數 能夠配置的更高

7.3 模板引擎優化

   通常秒殺頁面的首頁(其實裏面內容不多,就css,js連接)須要模板引擎渲染,可使用beetl ,

而且將渲染內容緩存。

8、安全性考慮

8.1 如何防止直接拿到下單URL? 

        爲了不用戶直接訪問下單頁面URL,須要將改URL動態化,即便秒殺系統的開發者也沒法在秒殺開始前訪問下單頁面的URL。辦法是在下單頁面URL加入由服務器端生成的隨機數做爲參數,在秒殺開始的時候才能獲得

8.2 如何控制秒殺按鈕點亮?

     使用js控制 ,js內容true、fasle,該js連接帶隨機版本號不被緩存,這個js很小 不會對形成影響。 

相關文章
相關標籤/搜索