秒殺之流控

01 秒殺帶來的問題和挑戰前端

秒殺場景下幾大問題:nginx

瞬時流量之高一方面形成的讀寫衝突,數據庫鎖會很是嚴重。redis

應用服務器負載高。spring

秒殺意味着各類活動,須要快速迭代業務,快速上下線,快速支持需求!docker

從系統上講咱們要作到高可用和高併發;從開發效率上咱們要作到敏捷開發以支持產品快速迭代。數據庫

若是把解決秒殺問題當作一種武林祕籍,則產品架構是內功,流量控制是招法,上乘內力搭配製勝招法則無往而不利。編程

 

02 內功-產品架構解決之道緩存

向一站式架構說」NO」

上圖是一個典型的一站式架構,一站式架構存在不少問題。tomcat

首先就是不易擴展,難以維護。服務器

一站式架構中的擴容每每創建在「既然什麼都沒改,則運行應該正常」的假設之上,而擴容遷移中的各類BUG則隱藏在這種假設之中。

其次是代碼難以理解,開發質量得不到保證。隨着系統規模的擴大,即使是最初通過良好設計的代碼,通過人員迭代,需求壓力,也不免會逐漸走向混亂。

最後在一站式架構下項目的可靠性是沒法獲得保證的,因爲業務調整而修改一處邏輯,每每會影響到代碼中不少功能的邏輯,而這些額外受到影響的功能則一般不會獲得測試,只是在假定這些都是正常的,而這種假定也一般正確,直接潛在的問題爆發。該出錯的總會出錯,墨菲定律每每這時候是最有效的。

綜上能夠看出一站式架構設計與敏捷開發格格不入,持續開發,持續集成,持續部署也就只能變成空談了。

 

03 微服務架構

上圖是優化後的微服務架構,將整個系統拆分紅訂單、推送、折扣、產品、我的信息等各個微服務,每一個服務都有本身的數據庫和緩存等,而且不會互相交叉。各服務之間使用消息隊列、RPC調用等傳輸數據。目前大部分系統設計可能處於一站式架構和微服務架構之間,即上層應用可能已經服務化,可是數據庫層面仍是使用同一個庫。但我的覺得系統應該朝徹底微服務化努力,隔離數據庫層面的共用,以得到更高的系統可靠性。

微服務架構下的系統更加容易進行擴展,能夠只針對須要擴容的系統來進行擴容,例如訂單量增大,能夠只擴容訂單服務,而對於其餘服務例如我的信息、折扣中心等都都不進行調整,這樣一方面減小了系統擴容而對總體穩定性帶來的變化,即只需測試新環境中的訂單服務便可,隨着微服務拆分的越細,這種優點也就越大。

在這種微服務架構下,開發人員能夠更加集中精力,將重點放到少許的代碼和明確的業務上,這樣可以產出更加優雅的代碼和良好的設計,在代碼優化調整中,也不會因爲處處調用而畏手畏腳。每一個微服務能夠安排2-3人的小組專門維護,這樣也會減小一個微服務內部的溝通成本,而進一步提升生產力。每一個微服務小組能夠獨立工做,無需過多協調便可實踐新功能或想法。

隨着技術的不斷髮展,項目所用的技術架構總會過期,在系統技術革新上,對於傳統的一站式架構,甚至是以前提到的服務化架構在應用新技術上都會遇到不小的困難,牽一髮動全身,技術改革每每除了推倒重來而沒有其餘辦法。對於微服務架構,因爲系統的徹底拆分,公共組件依賴只剩下異步的消息隊列,在新技術應用這方面則有了自然優點。微服務基於組件開發設計,提供了在開發過程當中技術選型的最大靈活性,甚至是編程語言的變化均可以進行嘗試。

最後要提到的,就是系統穩定性和可用性方面的考慮。在業務需求的持續推進下,持續部署不可避免,在線系統隨時都須要進行上線。隨着業務的增加、系統的複雜,系統部署時形成問題的潛在可能性會大大提升。而微服務在這方面極大的提升了系統的可靠性。因爲微服務的劃分,故障自然被隔離,某個服務的故障,不會形成系統的總體癱瘓。而發佈的時間因爲只須要發佈更新相關的服務而大大縮短,這也提升了總體系統的穩定性。當面臨問題須要回滾時,也只須要回滾更新相關服務便可,而這在一站式架構中將會是一個災難。

良好的架構能夠更好的支持快速迭代。高內聚的設計將開發人員精力集中到相對集中的領域以設計更優雅的代碼實現。隨着技術的演進,項目架構也能夠跟着一塊兒迭代升級。也能夠更好的支持持續集成、持續部署。總之,微服務能夠滲透到開發中的每一個領域爲業務迭代提供更好的支持。微服務這方面建議能夠參考spring clound和docker。

 

04 招法-流量控制解決方案

 

內功的修煉當然重要,不過並不是一朝一夕可成,是須要長期的努力和不斷的沉澱。在武學中當然有高神內力,同時也存在一些致勝招法,一旦練成便可功力猛進,下來就讓咱們看一下支持秒殺業務中的一些致勝招法:流量控制解決方案。

 

05 流量控制解決總覽

  如上圖所示,在項目的整個架構中,流量要作到逐層減小。在每層中均可以使用一些方法來減小流量。

 

06 前端流量控制

前端流量控制,頁面能夠設計爲動靜分離,將盡量多的數據使用CDN進行緩存,以減小到本身服務器上的流量。同時能夠加入驗證問題,拉長用戶下單時間並防止刷單。對較核心邏輯擔憂用戶破譯驗證方式,能夠再增長服務器端的用戶ID訪問限制,例如同一用戶5s內只能觸發1次相關操做等。

 

07 反向代理流量控制

反向代理(nginx)流量控制,不少頁面或者接口響應數據均可以進行靜態化處理,應用側(tomcat)能夠定時生成這些資源,發到內容分發服務上,內容分發服務能夠將這些靜態化資源分發到全部的反向代理上。這些數據能夠根據須要按照必定時間間隔進行更新。同時,也能夠利用nginx中的緩存配置功能,對熱點接口進行緩存。

藉助nginx中nginx-lua插件的功能,一些簡單邏輯在nginx中直接實現會比較容易,使用恰當,可以大幅減小到應用服務器的請求。例如倒計時,取系統當前時間等邏輯就很是適合在nginx中使用lua實現。對於存在緩存中的商品數量等信息也可由nginx直接訪問緩存返回,而不將請求再轉發給應用服務器。

 

08 訪問數據分析流量控制

在秒殺中,使人頭疼的問題不僅是正常流量突增。因爲秒殺活動通常都帶有優惠性質,惡意訪問也會增多,對於惡意請求在nginx層也能夠作不少工做,進行一次攔截。nginx配置中有限制用戶訪問頻率的配置能夠根據須要進行配置。同時,也可使用nginx-lua完成一些簡單的封禁邏輯,例如調用接口能夠封掉指定IP或者UA的訪問請求。以後利用日誌分析程序,對訪問日誌進行分析,將須要封掉的IP或者UA等信息調用nginx上提供的接口進行封殺。

 

09 應用服務器流量控制

通過以前的處理,可以到達應用服務器的流量已經少了不少。對於秒殺活動這類的需求,能夠準備專門的活動服務器,專門處理相關邏輯。可使用不一樣域名進行分流,或者按照必定URL規則在反向代理服務器上進行分流。同時,對於到數據庫進行操做的請求可使用阻塞隊減小到數據庫的訪問以減小行鎖等。對於明顯超出處理範圍的請求能夠直接返回秒殺已經結束。例如商品總量300,剩餘量100,每臺應用服務器上待處理的值超過總量的值則能夠直接返回秒殺結束。剩餘量能夠存入緩存服務中,剩餘量能夠不那麼精確,確保緩存中的剩餘量>=實際剩餘量便可。超出剩餘量的請求也能夠直接返回秒殺結束。

緩存存儲多點部署以提升系統的總體可用性,避免緩存問題致使系統出錯的狀況。redis會是一個目前比較好的選擇,主從自動切換等功能能夠更好的加強系統總體可用性。對於使用單點memcache等系統,建議能夠配置keepalived,使得發生機器故障時,IP能夠自動轉移到另一臺健康memacahe服務器上,雖然數據不可恢復,可是緩存組件依然可用。宕機的組件對系統形成的影響每每是不可預料的,尤爲是在未良好設計的系統中,總體架構中應任一組件徹底宕機的可能性。

對於秒殺活動需求,多是一系列的活動,相關邏輯能夠判斷是否能夠作到一個專門活動庫中,並進行讀寫分離設計。有條件的狀況下,數據庫中間件會完成其中一部分工做。在沒有相關條件的時候,即便沒有數據庫中間件,相關邏輯也能夠直接在代碼中實現。

對於數據庫行鎖問題,若有須要能夠進一步優化,例如上圖,將行鎖問題經過拆分具體商品,增長分配ID標誌,去掉行鎖。這個變更的缺點是可能對現有業務邏輯影響較大。不過優勢也很明顯,在數據庫層面消除了行鎖。

 

10 流量控制總結

 

一圖勝千言,以上討論的流量控制總結方案能夠總結到一張圖上:

 

11 總結

 

結合微服務架構,咱們最終的架構圖能夠是這樣的:

以上供你們參考。

文章來源

做者:胡因可 || 網易樂得技術團隊

來自:tech.lede.com/2017/02/17/rd/server/seckill/

相關文章
相關標籤/搜索