本篇為Redis性能問題診斷系列的第二篇,本文主要從應用發起的典型命令使用上進行講解,由於Redis為單線程服務架構,對於一些命令如果使用不當會極大的影響Redis的性能表現,這裡也會對不合理的使用方式給出優化解決方案。 ...
(本文首發於“資料庫架構師”公號,訂閱“資料庫架構師”公號,一起學習資料庫技術) 本篇為Redis性能問題診斷系列的第二篇,本文主要從應用發起的典型命令使用上進行講解,由於Redis為單線程服務架構,對於一些命令如果使用不當會極大的影響Redis的性能表現,這裡也會對不合理的使用方式給出優化解決方案。
![](https://img2022.cnblogs.com/blog/2928967/202209/2928967-20220913221406550-1323485050.jpg)
- 由於大Key的記憶體分配及釋放開銷變大,直接影響就是導致應用訪問Redis的響應變慢;
- 刪除時會造成較長時間的阻塞並有可能造成集群主備節點切換【4.0之前的版本有這個問題】;
- 記憶體占用過多甚至達到maxmemory配置,會造成新寫入阻塞或一些不應該被提前刪除的Key被逐出,甚至導致OOM發生;
- 併發讀請求因為Key過大會可能打滿伺服器帶寬,如果單機多實例部署則同時會影響到該伺服器上的其它服務【假設一個bigkey為1MB,客戶端每秒訪問量為1000,那麼每秒產生1000MB的流量】;
- 運維麻煩,比如RedisCluster的數據跨節點均衡,因為均衡遷移原理是通過migrate命令來完成的,這個命令實際是通過dump + restore + del三個命令組合成原子命令完成,如果是bigkey,可能會使遷移失敗,而且較慢的migrate也會阻塞Redis正常請求;
- 分片集群RedisCluster中的出現嚴重的數據傾斜,導致某個節點的記憶體使用過大;
- 對於集合類型的Hash、List、Set、ZSet僅僅統計的是包含的成員個數,個數多並代表占用的記憶體大,僅僅是個參考;
- 對於高併發訪問的集群,使用該命令會造成QPS增加,帶來額外的性能開銷,建議在業務低峰或者從節點進行掃描。
- 降低使用 O(N) 以上複雜度的命令,對於數據的計算聚合操作等可以適當的放在應用程式側處理;
- 使用O(N) 複雜度的命令時,保證 N 儘量的小(推薦 N <= 500),每次處理的更小的數據量,降低阻塞的時長;
- 對於Hgetall、Smembers操作的集合對象,應從應用層面保證單個集合的成員個數不要過大,可以進行適當的拆分等。
- 是否有定時任務的腳本程式,定時或者間隔性的操作Redis
- Redis的Key數量出現集中過期清理
- 被動過期:只有應用發起訪問某個key 時,才判斷這個key是否已過期,如果已過期,則從Redis中刪除
- 主動過期:在Redis 內部維護了一個定時任務,預設每隔 100 毫秒(1秒10次)從全局的過期哈希表中隨機取出 20 個 key,判斷然後刪除其中過期的 key,如果過期 key 的比例超過了 25%,則繼續重覆此過程,直到過期 key 的比例下降到 25% 以下,或者這次任務的執行耗時超過了 25 毫秒,才會退出迴圈
- allkeys-lru:清理最近最少使用(LRU)的Key,不管 key 是否設置了過期時間
- volatile-lru:清理最近最少使用(LRU)的Key,但是只回收有設置過期的Key
- allkeys-random:隨機清理部分Key,不管 key 是否設置了過期時間
- allkeys-lfu:不管 key 是否設置了過期,清理訪問頻次最低的 key(4.0+版本支持)
- volatile-lfu:清理訪問頻次最低且設置了過期時間 key(4.0+版本支持)
- volatile-random:隨機清理部分設置了過期時間的部分Key
- volatile-ttl:清理有設置過期的Key,嘗試先回收離 TTL 最短時間的Key
- noeviction:不清理任何Key,當到達記憶體最大限制時,當客戶端嘗試執行命令時會導致更多記憶體占用時直接返回錯誤(大多數寫命令,除了 DEL 和一些例外)。
- 合理預估記憶體占用,避免達到記憶體的使用上限。這裡有兩種方法可以參考:
![](https://img2022.cnblogs.com/blog/2928967/202209/2928967-20220913221406467-534590901.jpg)
- 設置合理的Key過期時間,滿足業務的最小保留時間即可。
- 數據量過大建議拆分成多套Redis或者使用RedisCluster分片集群,建議單集群最大記憶體不超過20G。
- 數據清理策略改為隨機模式,隨機清理比 LRU 要快很多(不過這個要根據業務情況評定,業務優先滿足原則)。
- 如果使用的是 Redis 4.0 及以上版本,開啟 layz-free 機制,把淘汰 key 釋放記憶體的操作放到後臺線程中執行(配置 lazyfree-lazy-eviction = yes)
- 增加剩餘可用記憶體的監控,提前預警併進行最大記憶體上限的擴容或者提前清理釋放記憶體。
![](https://img2022.cnblogs.com/blog/2928967/202209/2928967-20220913221406677-2041051265.jpg)
![](https://img2022.cnblogs.com/blog/2928967/202209/2928967-20220913221406444-1178665281.jpg)