對於一個秒殺系統來說,瞬時的大量請求會對後臺服務造成衝擊,需要保證服務的可用性以及業務的正確性。
設計了一個高併發高可用的系統簡要流程架構如下圖:
1.將商品(或券)的信息等靜態數據放到cdn節點,實現動靜分離
2.業務請求和業務處理之間使用MQ對請求進行削峯
3.讀寫分離:對於邏輯複雜(用戶驗證,風控管理,行爲分析)的系統,可以將讀寫部署兩套服務進行分離
4.使用緩存:
- 像庫存這種信息無法放到靜態頁面,爲了應對大併發讀問題,可以在服務端做本地緩存用於讀取,一般緩存時間設置爲數秒,緩存失效時(最好在失效前一兩秒)重新拉取redis中的庫存信息。防止超買問題由扣減行爲保證,因此即使和緩存不一致,讀本地緩存也不會導致超賣,讀場景一般允許髒數據情況。
- 高併發時,大量的mysql操作會有很大性能問題,因此使用redis集羣作爲緩存進行讀取。
5.防止緩存雪崩:
- 減少緩存滲透:可以在服務中進行布隆過濾,可以將不存在的商品或券訪問在服務端過濾掉;或者對緩存中沒有的數據key置爲null並設置較短的過期時間,優點是簡單易操作,缺點要增加大量的null key,增大了與mysql的不一致性,需要消息機制和mysql保持同步
- 限流:對key的操作加鎖排隊(利用setnx進行分佈式鎖),即同時只允許一個線程訪問。
- 防止緩存同時失效:設置key的過期時間時,採用固定時間+隨機時間的方法,可以有效防止緩存同時過期引起雪崩的問題
- 增加二級緩存: A1爲原始緩存,A2爲拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置爲短期,A2設置爲長期。
6.合理設置redis中的key,使其均勻的分佈到各個節點,防止大量請求訪問到少量節點的熱點問題,而且可以減少單個節點宕機造成的影響。
7.由於商品或券具有獨立性, 每個商品或券分配一個獨有id,可以根據id範圍劃分到各個服務集羣中,服務在訪問對應範圍的的redis緩存,這樣可以大大增加訪問的併發性。實現方式一個是在web服務中將id路由到對應的消息隊列topic中,另一個是在消息隊列後部署消息路由集羣,相對來說方案一更好,因爲方案而增加了鏈路長度和故障點。
8.在7的基礎上,爲了進一步提升性能防止少量熱點數據影響全量數據的操作性能,可在服務中統計熱點數據(比如LRU),並將熱點數據獨立存放到一個集羣中去,這樣可以將熱點數據和其它數據隔離開來。當然這樣會增加熱點數據遷移的工作,增加了系統的複雜性。