首頁 > 軟體

Redis 鍵值設計使用總結

2023-04-08 06:01:50

前言

對redis的使用,想必做過後端開發的同學都不陌生,redis為key/value非關係型資料庫,使用起來簡單高效,支援的資料型別也比較豐富,幾乎在日常開發中沒有不涉及的;

但如果對redis使用比較深入的話,還需要綜合考慮多方面的因素,比如使用redis時如何兼具高效與效能,如何設計合理的key以達到存取時最高效等等,這都是應該考慮的,下面結合redis中一個比較簡單但也容易的問題,關於redis的鍵值設計做一個全面的探討;

Redis使用中不規範的現象

  • Redis 儲存的key命名不規範,比較隨意;
  • Redis 被當成儲存庫使用,存在資料丟失風險,且無重新載入方案;
  • Redis 快取key,未設定過期時間, 快取低頻資料佔用大量記憶體, 進而導致服務崩潰;
  • Redis 快取大量big key, 應用獲取時會佔用大量網路頻寬,刪除也容易造成阻塞;
  • Redis 使用者端使用不當,導致其它使用者端連線timeout, 原因可能使用者端密碼錯誤,且沒有使用連線池,大量連線重試導致系統埠資源耗光;
  • Redis 使用者端命令使用不當,導致大量的慢查詢,影響其它應用業務,比如在業務高峰期時使用 keys* 或flushall 這樣的命令;

Redis 使用業務場景推薦與建議

  • 高並行場景:熱點資料快取, 可提升系統整體響應速度,降低資料庫IO壓力 ;
  • 限時場景:利用Redis expire命令設定session過期和續期、手機驗證碼等;
  • 排行榜: 利用Redis list 和 sorted sets 資料結構能實現各種複雜的排行榜應用;
  • 資料集合操作:利用Redis list、set、sorted set, 方便進行資料計算, 如交集、並集、差集等;
  • 連續簽到:可以利用redis的bitmap資料結構實現簽到相關的業務;
  • 計數器:利用Redis incr、incrby命令實現api呼叫次數統計, api限流等場景;
  • 分散式鎖:利用 Redis 的 setnx 功能來編寫分散式的鎖, 典型開源元件比如redisson;

如何設計出優雅的key

可以這麼說,線上關於redis的效能優化這個問題上,不合理的key的設計經常是引發問題的根因,究其本質,就個人看到的情況來說,大多數同學在對redis使用過程中,對於key的設計幾乎是沒有什麼概念的,因為大多數同學使用的場景就是 key/val ,對應的資料結構就是 字串key/字串val;

稍微對redis有更深入的瞭解的同學,在進行儲存時,可能會知道 key的設計儘量短一點,中間最好有層次感,最好以 : 進行分割 ......

那麼如何才能設計出比較優雅的key呢?下面結合小編實際使用中的經驗以及踩過的坑,來具體談談;

一、遵循如下幾個最佳實踐約定

  1. 遵循基本格式:[業務名稱]:[資料名]:[id];
  2. key的長度不超過44位元組;
  3. 不要包含特殊字元;

關於上面幾條建議,這樣做有如下幾點好處:

  • 可讀性強,比如當我們設計這樣的key結構, order:user:10,一眼看過去就知道這是關於使用者訂單相關的key;
  • 方便維護管理,不同的應用,或者不同的業務採用不同的字首,在視覺化使用者端工具或者命令列中很方便進行key的查詢定位;
  • 避免key衝突,避免在使用過程中多個人都用userId這樣的值作為key引發的快取key衝突;
  • 更節省記憶體: key是string型別,底層編碼包含int、embstr和raw三種。embstr在小於44位元組使用,採用連續記憶體空間,記憶體佔用更小;

推薦值:

  • 單個key的value小於10KB;
  • 對於集合型別的key,建議元素數量小於1000;

二、儘量避免bigkey

1、什麼是bigkey呢

BigKey通常以Key的大小和Key中成員的數量來綜合判定,例如:

  • Key本身的資料量過大:一個String型別的Key,它的值為5 MB;
  • Key中的成員數過多:一個ZSET型別的Key,它的成員數量為10,000個;
  • Key中成員的資料量過大:一個Hash型別的Key,它的成員數量雖然只有1,000個但這些成員的Value(值)總大小為100 MB;

2、BigKey的危害

網路阻塞

  • 對BigKey執行讀請求時,少量的QPS就可能導致頻寬使用率被佔滿,導致Redis範例,乃至所在物理機變慢;

資料傾斜

  • BigKey所在的Redis範例記憶體使用率遠超其他範例,無法使資料分片的記憶體資源達到均衡;

Redis阻塞

  • 對元素較多的hash、list、zset等做運算會耗時較舊,使主執行緒被阻塞;

CPU壓力

  • 對BigKey的資料序列化和反序列化會導致CPU的使用率飆升,影響Redis範例和本機其它應用;

3、如何發現BigKey

在安裝的機器上執行 redis-cli --bigkeys命令

  • 利用redis-cli提供的--bigkeys引數,可以遍歷分析所有key,並返回Key的整體統計資訊與每個資料的Top1的big key;

通過scan掃描

  • 編寫程式,利用scan掃描Redis中的所有key,利用strlen、hlen等命令判斷key的長度(此處不建議使用MEMORY USAGE);

使用第三方工具

  • 利用第三方工具,如 Redis-Rdb-Tools 分析RDB快照檔案,全面分析記憶體使用情況;

使用網路監控

  • 自定義工具,監控進出Redis的網路資料,超出預警值時主動告警;

三、使用恰當的資料型別

正如上面所說,很多初次使用redis的同學,對於很多業務場景,都是一個key/val的簡單的結構搞定,而不會深入思考這樣做是否合理,或者說這樣做以後會不會引發相關的效能方面的問題;

對於這個問題,從根本上來說,需要深入瞭解並掌握redis的常用的資料型別,在這個基礎上,才能針對不同的業務場景,設計出高效的儲儲存存結構資料;

讓我們思考一下,如何快取使用者物件列表這樣的資料呢?

  • 方案1:key為usrId,value為物件的序列化字串,資料結構類似下面這樣; 

優點:存取方便,簡單粗暴,存取時只需要做下json和物件的互轉即可;

缺點:資料耦合,不夠靈活,一旦物件新增了欄位或刪減了欄位,快取重建的成本非常大;

  • 方案2:使用一個list結構,快取使用者ID列表,資料結構如下;

優點:對記憶體的佔用小,操作高效;

缺點:獲取到val之後,需要進一步查庫才能得到完整的物件;

方案3:使用hash結構,快取物件,資料如下所示;

優點:底層使用ziplist,空間佔用小,可以靈活存取物件的任意欄位;

缺點:編碼上相對複雜;

Redis 快取在實際應用中的使用建議

  • 【推薦】對快取進行預熱。在存取資料前,應先對快取進行預熱,避免大量請求直接進入資料儲存層;應根據業務情況劃分合適的冷熱資料,對熱點資料進行預熱。如許可授權資訊, apikey等;
  • 【推薦】配合使用本地快取。使用本地快取能更穩定、更快速地存取到資料,但在分散式架構下,要慎用本地快取,避免造成伺服器節點帶狀態。同時由於本地快取直接佔用應用伺服器的資源,要避免過度佔用資源導致應用節點崩潰;
  • 【推薦】快取變更策略,應先更新資料庫,再更新快取;
  • 【推薦】一次業務呼叫需要存取多次redis伺服器端,可採用pipleline或其它批次操作方式;
  • 【推薦】大List,Set,Hash,儲存的數量巨大。獲得大量元素時延遲較大阻塞其他命令.建議切割成多個小的list,set,hash;

使用業務規範

不管是redis,還是其他開發中使用到的中介軟體,具體到開發使用時,最好都應該提前制定出一套合理的規範,這個規範應該是大多數開發人員認可並在實踐中得到檢驗,且能有效規避一些問題的,一旦指定為規範,應該成為指導內部開發人員日常的規則,這裡提如下幾點:

  • Redis 應該定位為快取資料, 不可用於儲存大規模資料(不可替代資料庫);
  • Redis 適合讀多寫少場景,如存在高頻寫入,低頻查詢場景,則不推薦使用;
  • 在不確定key的存活時間時,最好設定過期時間,控制 key 的生命週期;
  • 應該考慮冷熱資料分離,對於查詢, 高頻次業務查詢走Redis,低頻查詢考慮走資料庫;
  • Redis 有資料丟失風險,程式處理資料時,應該考慮資料丟失後能自動從資料庫載入並快取到Redis;
  • 謹慎使用O(N)命令, 如list, set, hash 資料結構操作時, hgetall、lrange、smembers、zrange等並非不能使用,優先考慮使用 hscan、sscan、zscan 代替。

以上就是Redis 鍵值設計使用總結的詳細內容,更多關於Redis 鍵值設計的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com