Redis系列24:Redis使用規範

Brand發表於2023-09-28

Redis系列1:深刻理解高效能Redis的本質
Redis系列2:資料持久化提高可用性
Redis系列3:高可用之主從架構
Redis系列4:高可用之Sentinel(哨兵模式)
Redis系列5:深入分析Cluster 叢集模式
追求效能極致:Redis6.0的多執行緒模型
追求效能極致:客戶端快取帶來的革命
Redis系列8:Bitmap實現億萬級資料計算
Redis系列9:Geo 型別賦能億級地圖位置計算
Redis系列10:HyperLogLog實現海量資料基數統計
Redis系列11:記憶體淘汰策略
Redis系列12:Redis 的事務機制
Redis系列13:分散式鎖實現
Redis系列14:使用List實現訊息佇列
Redis系列15:使用Stream實現訊息佇列
Redis系列16:聊聊布隆過濾器(原理篇)
Redis系列17:聊聊布隆過濾器(實踐篇)
Redis系列18:過期資料的刪除策略
Redis系列19:LRU記憶體淘汰演算法分析
Redis系列20:LFU記憶體淘汰演算法分析
Redis系列21:快取與資料庫的資料一致性討論
Redis系列22:Redis 的Pub/Sub能力
Redis系列23:效能最佳化指南

1 Redis 操作規範

1.1 快取的使用時機判斷

  1. 【建議】系統為單體系統,整體QPS小於200的,不建議草率引入快取,應該有更多的辦法進行效率提升
    快取的引入根據系統的業務流量、應用規模而定,對於系統規模小低併發低流量的應用而言,引入快取並不會帶來效能的顯著提升,反而會帶來應用的複雜度以及較高的運維成本。
  2. 【建議】響應能力,資料響應的正常容忍度為0.5s,臨界容忍度為2s,當我們發現響應時間超建議值,並沒有太大最佳化空間的時候,可以考慮加入快取。
    說明:建立在對資料具有高效響應的需求的時候,快取是基於記憶體對映的,相對於磁碟存取來說會快很多。
  3. 【建議】熱點資料,這邊指的是同一個系統中的相對熱點資料,20%的資料佔據了整個請求週期(比如24小時)的80%的流量,那就建議在這20%的流量上做快取。
    對於熱點資訊被頻繁讀取,為避免資料庫超載的IO操作的情況下,可以適當使用快取進行緩衝。
  4. 【建議】讀寫比例,快取應該建立在多讀少寫(高頻讀取、低頻修改)的業務場景中。
    一般讀寫比要達到 9 : 1,讀比例越高越好,這樣建立快取的價值比較大。

1.2 快取型別的使用建議

1.2.1 資料型別

image
1.2.2 字元文字(REDIS_STRING) 適用場景建議

  1. 【建議】選型為簡易文字類快取 :比如普通的字元、文字、Json結構 ,通常能起到加速讀寫和降低後端壓力的作用。
  2. 【建議】計數場景:用於對數值進行增減,同樣適用於分散式系統的增量和減量計算
    • incr/decr key // 自增1
    • incrby/decrby key increment // 增加指定數值
    • incrbyfloat/decrbyfloat key increment // 增加一個浮點數
  3. 【建議】共享Session:在分散式系統中,使用者的每次請求會訪問到不同的伺服器,這就會導致 session 不同步的問題。

1.2.3 列表(REDIS_LIST)適用場景建議

  1. 【建議】訊息佇列:列表用來儲存多個有序的字串,既然是有序的,那麼就滿足訊息佇列的特點。使用lpush+rpop或者rpush+lpop實現訊息佇列。
  2. 【建議】棧:由於列表儲存的是有序字串,滿足佇列的特點,也就能滿足棧先進後出的特點,使用lpush+lpop或者rpush+rpop實現棧。
  3. 【建議】有序的物件列表:列表的元素不但是有序的,而且還支援按照索引範圍獲取元素。比如我們可以使用命令lrange key 0 9分頁獲取文章列表。
    說明:朋友圈的點贊列表、評論列表、排行榜:lpush命令和lrange命令能實現最新列表的功能,每次透過lpush命令往列表裡插入新的元素,然後透過lrange命令讀取最新的元素列表。

1.2.4 雜湊表(REDIS_HASH)適用場景建議

  1. 【建議】key、field、value結構場景,如購物車:hset [key] [field] [value] 命令, 可以實現以使用者Id,商品Id為field,商品數量為value,恰好構成了購物車的3個要素。
  2. 【建議】物件儲存場景:hash型別的(key, field, value)的結構與物件的(物件id, 屬性, 值)的結構相似,也可以用來儲存物件。
    說明:Redis 中的Hash和 Java 的HashMap更加相似,是陣列+連結串列的結構,當發生 hash 碰撞時將會把元素追加到連結串列上,值得注意的是在Redis的Hash中value只能是字串。

1.2.5 集合(REDIS_SET)適用場景建議

說明:Redis 中的 Set和Java中的HashSet 類似,內部的鍵值對是無序、唯一 的。相當於一個特殊的字典,字典中所有的value預設都是一個NULL值。當集合中最後一個元素被移除之後,資料結構被自動刪除,記憶體被回收。

  1. 【建議】通用的HashSet 集合使用場景,對於Set中的取值、判斷、統計,新增跟移出都有很便利的支援。
    比如社交領域的 好友、關注、粉絲、感興趣的人 等場景:
    • sinter 命令可以獲得A和B兩個使用者的共同好友;
    • sismember 命令可以判斷A是否是B的好友;
    • scard 命令可以獲取好友數量;
    • 關注時,smove 命令可以將B從A的粉絲集合轉移到A的好友集合
  2. 【建議】Set具備隨機獲取能力,建議在一些對集合值隨機取數場景使用。
    類似首頁展示隨機:美團首頁有很多推薦商家,但是並不能全部展示,set型別適合存放所有需要展示的內容,而 srandmember 命令則可以從中隨機獲取幾個。
  3. 【建議】Set具備Single能力,建議在一些對集合值需要去重的場景中使用。
    類似儲存某活動中中獎的使用者ID ,因為有去重功能,可以保證同一個使用者不會中獎兩次。

1.2.6 有序集合(REDIS_ZSET)適用場景建議

說明:zset也叫SortedSet,一方面保證了內部 value 的唯一性,另方面它可以給每個 value 賦予一個score,代表這個value的排序權重,所以又具備排序功能。

  1. 【建議】帶排序條件的列表集合,比如排行榜場景,但是和list不同的是zset它能夠實現動態的排序,例如: 可以用來儲存粉絲列表,value 值是粉絲的使用者 ID,score 是關注時間,我們可以對粉絲列表按關注時間進行排序。
    另外如 儲存學生的成績, value 值是學生的 ID, score 是他的考試成績。 我們對成績按分數進行排序就可以得到他的名次。

1.3 快取的定義和使用規範

1.3.1 Key 定義規範

  1. 【必須】key的命名需遵循小寫原則,且不允許重複key,否則會產生覆蓋情況。
  2. 【必須】建議使用 “平臺縮寫“+“”+“專案名”+“”+“業務含義” 的英文作為key的字首,防止key衝突,用下劃線"_" 、":" 或 "." 作為間隔,字元包含A-Z,a-z,0-9,提高可讀性和可維護性。
    mt_shop_orderbidu_istio_userinfo
  3. 【必須】禁止使用redis保留字命名key。參考這邊
  4. 【建議】合理控制key的長度,避免使用過長的key或者過簡單的key,減少記憶體消耗並增加易讀性,一般key長度不建議超過30字元;
  5. 【必須】禁止使用特殊字元:如空格、換行符、單雙引號及其他跳脫字元等;
  6. 【建議】避免使用超大field的複雜型別物件,超大型別的field需要進行切割;

1.3.2 Value 使用規範

  1. 【必須】禁止使用bigkey,防止網路卡流量過載和慢查詢,如:string型別控制在10KB以內,hash、list、set、zset 元素個數不要超過5000;
  2. 【建議】非字串的bigkey,儘量避免使用整體 del刪除,使用hscan、sscan、zscan方式漸進式刪除,可pipeline加速,同時要注意防止bigkey過期時間自動刪除問題導致的效能損耗;
  3. 【建議】選擇合適的資料型別,節省記憶體,提高效能; 我們在資料型別的使用規範建議那邊有提出了建議。

1.3.3 例項及資源使用規範

  1. 【建議】單一職責原則:一個業務使用一個例項,避免多個業務共用一個例項;
    這個是指做Redis例項拆分的時候,儘量按照業務領域去拆分。並不是指一個業務程式只能呼叫一個快取例項。
    做隔離一方面是避免業務相互影響,另一方面避免單例項膨脹,並能在故障時降低影響面,快速恢復。
  2. 【建議】單個例項最大記憶體佔用率使用不能超過實體機的80% 。 指標:保證 ≤ 80%, ≤ 50% 優
  3. 【建議】單個例項最大CPU佔用率使用不能超過實體機的70% 。指標:保證 ≤ 70%以內,≤ 50 % 優
  4. 【建議】按業務線合理預估記憶體使用大小(一般為6個月 - 24個月);
  5. 【建議】分析快取命中率,快取的命中率應該高達80%以上,至少不低於 60%,否則需檢查是否有不合理的快取使用。
  6. 【建議】為快取例項指定對應的服務應用,同一個服務下的不同例項可以直連訪問。其它服務需要訪問則要透過介面進行訪問。

1.3.4 垃圾回收及失效規範

  1. 【必須】提前評估資料的生命週期,合理設定資料過期時間和實效策略,如無特殊情況,所有key必須均設定過期時間;
  2. 【必須】避免使用系統自帶的自動過期時間機制;
  3. 【建議】定期手動清理資料空間,避免殭屍快取佔用空間;
  4. 【建議】批次建立的快取需要打散過期時間,防止集中過期導致資料不可恢復帶來的影響; 一般我們採用 n * 3/4 + n * random() 。所以,如果是8小時,就是6小時 + 0~2小時的隨機值。
    image
  5. 【必須】儘量避免將快取持久化,這也是Redis官方的建議,需要將快取持久化的項(無論是AOF還是RDB)或者無過期時間的項,均需嚴格報備評審並做記錄,無用時需嚴格銷燬。

1.3.5 命令使用規範

  1. 【建議】控制列表長度N的數量,一般控制在1W以內,有遍歷的需求可以使用hscan、sscan、zscan代替;
    一個列表最多可以包含 2^32 - 1 個元素 (4294967295, 每個列表超過40億個元素),但是如果列表太長,就跟它快取記憶體的目標相悖
  2. 【必須】禁止使用keys、flushall、flushdb等操作;
    • KEYS:該命令需要對 Redis 的全域性雜湊表進行全表掃描,嚴重阻塞 Redis 主執行緒;(應該使用 scan 來代替,分批返回符合條件的鍵值對,避免主執行緒阻塞)
    • FLUSHALL:刪除 Redis 例項上的所有資料,如果資料量很大,會嚴重阻塞 Redis 主執行緒;
    • FLUSHDB,刪除當前資料庫中的資料,如果資料量很大,同樣會阻塞 Redis 主執行緒。(加上 ASYNC 選項,讓 FLUSHALL,FLUSHDB 非同步執行)
  3. 【建議】使用批次操作,提高效率,控制一次性操作元素個數,建議為500;
    說明:獲取集合中的元素(HASH 型別的 hgetall、List 型別的 lrange、Set 型別的 smembers、zrange 等命令)。如果全量或大量操作會對整個底層資料結構進行全量掃描 ,導致阻塞 Redis 主執行緒。
  4. 【建議】減少事務的使用(redis暫時不支援事務回滾);
  5. 【必須】掃描涉及元素數量比較大且設定過期時間的禁止使用scan;

2 Redis 高可用操作規範

說明:本標準以業內現有的主流分散式資料儲存服務能力 為參考,建議讀者在設計具備高可用快取服務的時候,可以透過以下幾個部分進行衡量。

2.1 高可用叢集模式設計

主要包含三種模式:常規的主從模式,哨兵模式,和高擴充套件的分散式叢集,配合使用。讀者在在設計的時候,根據業務規模和具體實現情況進行選擇。

  1. 【必須】最低要求,主從叢集模式下,需保證如果主庫發生故障,能夠識別到即對主從進行切換,並利用心跳包進行探活並恢復。
  2. 【建議】儘量滿足,哨兵模式下,會有對應的競選機制,對故障進行下線,對新主機進行競選。
  3. 【建議】儘量滿足,分散式叢集下,支援對叢集的 負載均衡、強事務、故障離群和恢復能力。
    ★設計建議參考業內競品作為準入標準,如DBProxy 包含 Sentinal程式,為探活、故障離群和故障恢復提供很好的幫助。

2.2 安全建設能力設計

設計時需要保證如下基本要求:

  1. 【必須】對於敏感資料進行加密,如身份證、電話、使用者住址等,密碼類需保證不可逆。
  2. 【必須】支援IP黑白名單配置,避免非法IP的惡意訪問。
  3. 【必須】對於SQL入侵、注入有比較好的檢測和隔離,非法字元的過濾和轉義,這個需要武裝到程式級別上,業內已經有很標準的方案了。
    准入的標準就是攔截率超過 95%,準確率99.9%(需避免誤攔截正確的請求)以上。
  4. 【必須】核心模組有標準的操作記錄(如 操作模組、操作人員、操作時間、資料變動、說明),支援SQL安全審計。

2.3 備份與恢復能力設計

  1. 【必須】支援定時自動備份(編寫備份指令碼自動執行 或者 任務服務去定時執行)和手動備份
  2. 【必須】支援定期的全量備份 Week級別、Month級別 ,和定期 Day級別 的增量備份
  3. 【必須】有完整的災備恢復操作文件 和 定期演練機制,保證 恢復速度10G/min ,資料完整性99.99%,恢復成功率:99.99%。

2.4 高可用架構-異地多活

異地多活

  1. 【建議】異地多活,多IDC,能保證非強同步(即非同步同步),也就是說資料保持最終一致性,並非強一致性。
  2. 【建議】多主之間需保證支援至少 1W TPS傳輸峰值達到 10M/s。
  3. 【建議】機房具備容災:建議多IDC部署,避免單個機房掉電、火災、網路故障 導致整個系統不可用。
  4. 【建議】需保證單機房異交換機部署方式,具備一定的高可用能力。可以部署多個節點,部分節點掛掉後不影響業務;
    資料節點支援多副本,單節點掛掉後,不影響業務,管理節點具備高可用性,支援多個節點部署。
  5. 【建議】異地機房如果只是用作備服,非同步同步可以允許有些許資料延遲,延遲時間不應超過5分鐘。
    異地的資料中心 主 - 主 同步採用的是非同步同步,如下圖所示,是非同步獲取的,會因為延遲導致的資料暫時不一致性。
    image

2.5 快取擊穿、快取雪崩、快取穿透預防設計

2.5.1 隨機過期時間(參考1.3.4 第 4點做法)

2.5.2 大資料集合場景啟用BloomFilter

參考這篇:布隆過濾器

2.5.3 短暫降級:空初始值

參考這篇:再聊快取擊穿,面試是一場博弈

2.5.4 計算服務層或資料服務層降級、限流

完整策略參考這篇:快取的雪崩預防設計

3 流程上的約束

  1. 建立嚴格的程式碼評審機制和刷庫評審機制。操作Redis的程式碼提交合並或者指令碼提交刷庫執行之前需要上級評審/交叉評審。
  2. 引入開源評審工具。增加掃描工具、指令碼進行定期檢查MySQL、Redis。

相關文章