「每日分享」秒殺之流控

點擊上方"java全棧技術"關注,每天學習一個java知識點,喜歡的也可以關注WX號"ITeye"

01 秒殺帶來的問題和挑戰

「每日分享」秒殺之流控

秒殺場景下幾大問題:

瞬時流量之高一方面造成的讀寫衝突,數據庫鎖會非常嚴重。

應用服務器負載高。

秒殺意味著各種活動,需要快速迭代業務,快速上下線,快速支持需求!

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

如果把解決秒殺問題看成一種武林秘籍,則產品架構是內功,流量控制是招法,上乘內力搭配製勝招法則無往而不利。

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

向一站式架構說”NO”

「每日分享」秒殺之流控

上圖是一個典型的一站式架構,一站式架構存在很多問題。

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

一站式架構中的擴容往往建立在“既然什麼都沒改,則運行應該正常”的假設之上,而擴容遷移中的各種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/


分享到:


相關文章: