Redis高併發處理常見問題及解決方案

1. 大型電商系統高流量系統設計

  場景:
    大量電商系統每天要處理上億請求,其中大量請求來自商品訪問、下單。商品的詳情是時刻變化,由於請求量過大,不會頻繁去服務端獲取商品信息,導致服務器壓力極大。需要用到多級緩存、異步處理、負載均衡等方式來實現
  解決:
    評估哪些頁面是活躍的,即用戶查看使用較多的頁面。頁面裏面包括靜態資源和數據、動態數據等,劃分層次,把靜態資源存放到負載均衡服務器中緩存,如Nginx本地緩存。頁面中的動態數據分爲熱點數據、非熱點數據、實時數據、非實時數據等。把非熱點數據、熱點數據、非實時數據存放到Varnish緩衝中,Varnish擅長存儲不變或變動較少的數據,通過Varnish的緩存策略,減少請求後端服務器的頻率
    Redis緩存存儲熱點數據、實時數據,Redis擅長存儲需要原子操作計算、全局主鍵生成、訂單號生成、排序相關數據。高併發情況下實時的數據處理講究快速響應,爲了提高效率可以採用異步消息隊列處理。
    系統架構採用了Nginx本地緩存、Http加速Varnish緩存、後端Redis緩存、消息隊列等。注意:Nginx緩存靜態資源、Varnish緩存不變或變動較少的數據、Redis緩存原子操作計算數據,異步隊列主要處理非實時的業務或數據

 

2. Redis支撐百萬QPS高併發、高可用架構

  場景:
    大型電商系統每天有上億請求,會用到多級緩存,此時Redis單體無法承載需求量,需要使用Redis集體模式,由多態Redis共同承載並供外界使用
  解決:
    Redis單體處理併發能力達到10多萬,分析Redis的瓶頸在於確定是讀還是寫方面。如果在讀取數據方面在瓶頸時,可以採用讀寫分離、主從方式,通過哨兵監控服務正常性。主節點用於寫入數據,並同步數據至從節點,從節點可以部署多臺,整體提高Redis的讀取數據能力
    Redis主從模式:Redis集羣主從部署,一臺主節點寫入,多臺從節點讀取,主節點數據同步到從節點,數據延遲毫秒級別,同時引入哨兵模式監控,當主節點宕機後,進行選主操作,到從節點選舉一臺升級爲主節點,履行主節點的使命,當之前宕機的主節點恢復後,會加入到節點繼續服務
如果在寫方面存在瓶頸,可以採用Redis集羣化,由多臺Redis共同成立的虛擬組織機構共同提供外界寫入、讀取操作。Redis設置了合理的備份方案,防止數據丟失。集羣化後的Redis可以提供上百萬甚至上千萬的QPS併發處理,集羣部署

 

3. Redis雪崩後,備用方案

  場景:
    Redis集羣模式中,由於網絡、帶寬等其他異常情況導致Redis雪崩後,如何提供網站正常服務並處理大量請求?設計時需要考慮到容災,當Redis宕機後,監測到狀態,啓動其他緩存技術,如enCache、MemCache。注意,Redis和其他緩存之間需要定期同步數據,當Redis恢復後,切換到Redis
  解決:
    由於用戶量、請求量都較多,設計時需考慮到極端情況,即要考慮替代方案。當Redis異常情況雪崩,系統監控到Redis心跳停止後,切換到備用緩存,如Memcache、Encache等,崩潰的Redis由於備份恰當,以儘快恢復使用,恢復期間可以用其他緩存,Redis使用期間的數據需要和崩潰後的數據進行同步,保證數據最終一致性,可以採用消息隊列、備份文件對比複製等操作實現   

  > Web應用通過Lua腳本操作Redis時,發現其無心跳,會自動切換到其他緩存技術

 

 

4. 高併發情況下,數據庫和緩存雙寫數據不一致問題

  場景:
    當核心業務需同時操作Redis和數據庫時,由於兩者之間存在非原子操作,當操作其中之一成功後出現異常、導致兩者之間的數據不一致,應如何解決?可以引入異步消息隊列串行化執行
  解決:
    1. 數據庫先寫入成功,Redis後寫入失敗
    2. Redis先寫入成功,數據庫寫入失敗
    3. 操作數據和Redis串行化,使用消息隊列,由於其具有重試、吞吐量搞、消息持久化等特性個,可以通過消息隊列來保證雙寫數據一致性。
    先寫入Mysql,加入消息隊列,消費,寫入Redis緩存,一致性。消費隊列執行失敗後,因爲數據持久化,所以可以進行失敗重試處理。

 

 

5. 高併發Redis緩存中的大value存儲,全量更新時效率低

  場景:
    用戶量不高,可能會把商品、詳情等數據完全存儲在Redis中某個key對應value中,隨着用戶量逐漸增加,此時處理更新時,處理效率比較差,可以按照存儲信息的維度進行數據拆分,如商品信息可以按照商品的類別和批次進行拆分
  解決:
    由於Redis是單線程模式進行的,一次操作大的value會對整個Redis 的響應時間造成較大影響,所以業務上將其拆分成多個小key形式。可以按照功能的類別、批次維度進行拆分,建議每個key不要超過1MB


6. 高併發Redis防止緩存被穿透

  場景:
    當系統內使用緩存的地方的失效時間都一樣時,若系統高峯期間恰好緩存失效了,大量請求至緩存中,此時都沒命中,Redis的壓力瞬間飆升,緩存被穿透。根據系統結構U劃分,不同的操作需要設置不同的緩存失效時間,錯開讀取數據的時間,避免被穿透
  解決:
    高峯期間,系統受到諸多無效,如被攻擊等,可在應用程序中使用Redis的常用方式來避免
    處理流程如下:
      1. 根據商品的主鍵goodID去緩存中查詢商品,若商品存在即返回
      2. 若商品不存在,再去查詢數據庫
      3. 若數據庫中存在,將其存儲到Redis中,並設置過期時間
    被擊穿的情況:若高峯期間外界頻繁去請求這個接口方法,傳入的goodId有各種類型,此時去緩存中查詢,大部分是沒有數據的,然後這些請求會流入查詢db中,Redis由於高性能特性可以去處理這部分請求,但是數據庫中,由於數據庫的連接數存在瓶頸,大量請求去查詢數據庫會導致數據庫的CPU瞬間飆升,嚴重會卡死。
查詢Redis爲null,查詢數據庫也爲null,此時設置該key在緩存中,且值爲null,過期時間爲隨機時間。random(10)。這樣子能保證數據在這段時間暴力請求,也只會在這短暫的時間內獲取null,而有另外的線程在讀取數據庫表,並緩存在Redis中

7. 高併發Redis提高命中率

  場景:
    集羣部署Redis中,由於多臺Redis請求訪問的頻率存在不一致,導致Redis沒有充分被利用,爲了更好地提高訪問次數和命中率,可以在部署策略中通過Lua腳本實現一致性Hash流量分發
  解決:
    命中:可以直接通過緩存獲取數據
    不命令:無法直接通過緩存獲取數據,需要再次去數據庫表中查詢或者執行其他的操作。原因可能是由於緩存根本不存在或者緩存已過期
  當緩存有過期的key存在時,會導致命中率下降。Redis中提供了info函數來監控服務器的狀態,通過hits和miss計算命中率,14514119/(14514119+3428654)=82%,命中率較低,而一個良好的緩存存儲機制包含了失效機制、過期時間設計,命中率高達95%以上

 

 

8. 高併發Redis防止雪崩

  當Redis中的大量數據頻繁過期失效後,可能有大量請求來獲取數據,面臨擊穿,嚴重導致崩掉。可以用鍵值對失效時間合理設置、互斥鎖等方式來防止雪崩
  場景1:Redis緩存中,數據集體過期失效
    在Redis緩存中的某個時間節點,緩存的數據集中過期失效,導致緩存被擊穿,流量流向數據庫中,造成數據庫負載過高
  場景2:Redis緩存中,Redis集羣大批量機器故障
    在Redis集羣中大批量的機器故障,整體的穩定性和可靠性出現嚴重問題,不能給外界提供良好的服務,導致流量流向數據庫,造成數據庫負載過高
  預防緩存雪崩解決:
    1. 設計Redis緩存架構時,儘量設計高可用,防止大批量機器故障,當個別節點、部分機器出現問題後,不影響Redis整體的可用性
    2. Redis緩存存儲時,設計合理過期時間,錯開業務交叉存儲。合理的過期時間可以更大程度調高緩存的命中率,減少數據庫的壓力

9. 高併發Redis緩存預熱方案   

  場景:
    當系統熱點數據初始化被高頻率訪問時,嚴重會造成阻塞死鎖。可以在系統啓動時預加載到緩存中
  解決:
    系統啓動和核心功能使用之前進行緩存加載,如省市區、熱點數據,這些數據更新頻率較低,數據量較大,可以提前加載到容器中,當外界需要使用時,直接從緩存中,不需要查詢數據庫。那麼當數據更新時如何更新緩存呢?
    更新緩存有兩種模式:自動和手動。手動即人工觸發更新操作,把更新的數據流向緩存中。當緩存過期或失效後,可自動讀取數據庫數據然後加載到緩存中。爲了保證緩存的充分利用,建議將更新頻率較低的熱點數據設置爲永不過期,當數據改變時,可以用監聽通知等方式自動更新緩存的數據

 

 

10. 高併發Redis緩存擊穿

  場景:
    系統緩存中熱點的數據某個時間點即將過期,恰好這個時間節點訪問量突增,對於這個Key有大量的併發讀取操作,這時候擊穿了Redis,直接訪問到DB中,會對DB形成巨大壓力。可以設置熱點數據永不過期,熱點數據增加互斥鎖
  解決:
    通常Redis中會優先存儲熱點數據,由於熱點數據訪問頻率高,命中率會顯著提高。高併發中,熱點數據被頻繁訪問,當緩存熱點數據恰好過期,大併發請求集中訪問,持續的訪問會直接擊穿緩存,使流量直接流向數據庫,給數據庫造成較大壓力。那麼如何防止被擊穿呢?簡單可以設置熱點數據永不過期,當熱點數據發生更新時,通過監聽通知等方式,自動更新緩存數據

 

 

11. 高併發Redis緩存集中失效

  場景:
    緩存中由於存儲的數據過期時間固定且一樣,導致同時間數據過期,緩存被穿透甚至雪崩。可以合理設置不同類型的緩存時間,如基於隨機過期的緩存失效時間
  解決:
    Redis過期時間會直接影響命中率,爲了提高命中率,需要合理設置過期失效,過期時間設置需要分類,包括熱點數據、冷數據、臨時數據等
    1. 針對熱點數據設置合理過期時間,需要從用戶行爲統計分析、物品模型的數據存儲、物品被查看的次數等方面綜合考慮,設定一個合理的數值,建議可設長點
    2. 冷數據,一般被查看的次數、使用的頻率較低,爲了提高Redis整體的空間存儲,通常冷數據設置的過期時間較短
    3. 臨時數據,即無效或者臨時使用的數據,爲了避免緩存被穿透,通常設置一個臨時數據,過期時間設置較短

 

 

12. Redis高效拆分數據過程

  場景:
    系統構建初期使用單臺Redis提供服務,發展過快,用戶數量隨之增加,此時單臺Redis數據量過大,效率低下,會涉及Redis數據拆分遷移
  解決:
    以Redis數據拆分爲例,RedisA存在用戶、產品、訂單數據,可拆分成RedisA、RedisB、RedisC,分別存放用戶、產品、訂單數據。針對RedisA 、RedisB、RedisC還可以進行父子Master-Slave方式進行擴展,假如其配置是32G,按照5K條數據1MB,保守可以存儲2~3億數據

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章