窺探redis爲什麼會變慢

當今分佈式服務大行其道,微服務,微應用解耦的需求層層推動,這個時候,咱們常常會用到redis這款中間件做爲分佈式系統的緩存來使用,以提升系統應用的響應速度,或者說下降服務器的負載難度。那麼問題來了,redis速度快的flag是直接寫官網的公屏上,那咱們不妨來推演一下,redis變慢的緣由,知其然而知其因此然。html

窺探redis爲什麼會變慢

你們之言

Redis採用的是基於內存的採用的是單進程單線程模型的 KV 數據庫。官方提供的數據是能夠達到100000+的QPS(每秒內查詢次數),數據結構簡單,對數據操做也簡單,Redis中的數據結構是專門進行設計的。使用多路I/O複用模型,非阻塞IO。前端

問題1:redis真的只是單進程單線程嗎?redis

問題2:redis數據結構真的簡單嗎?數據庫

不可能單線程

從表面上看採用單線程,這樣避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU,甚至不用去考慮各類鎖的問題,所以不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗。然而當咱們在啓用rdb的時候,當咱們在啓用scan的時候,都是會啓用一個子進程來完成任務,而原來的主進程任務仍是在正常進行,對於系統來講可能會存在響應時間長一點的感知。只看表面的話,對於redis的認知是遠遠不夠的。後端

redis的數據結構很簡單?

嗯,redis的數據結構說簡單的話,純粹是菜鳥教程看多了緩存

窺探redis爲什麼會變慢

redis的結構有挺多的,主要是一下三種:服務器

  • 常見的數據結構:string、hash、set、sortset、list
  • 特殊結構:HyperLogLog、Geo、Pub/Sub
  • redis modult:BloomFilter,RedisSearch,Redis-ML

經過分類咱們一來知道這玩意由淺入深的複雜,二來知道經過不通的結構能夠處理不一樣的業務場景。對於業務場景的探討後續能夠展開講講,此次主要是想推演一下,在全部場景中挺常見的現象——變慢。網絡

redis爲什麼會變慢

隨着時間的堆積,數據的累增,系統很直觀的會感受的變慢的現象,對於大型程序來講,主要是內存碎片啊、堆棧溢出啊等等這些關於垃圾回收機制致使的,另外的仍是跟其餘組件在配合中,網絡開銷致使的現象,此次咱們主要是從redis自身進行分析。數據結構

基本性能

咱們應該先知道設備的基本性能,有數據比較纔有調優的依據,剛上線的設備性能應該是最優秀的,以後就須要考慮,上線的服務數據的分佈問題。多線程

基準性能

Redis 在一臺負載正常的機器上,其最大的響應延遲和平均響應延遲分別是怎樣的?

Redis 在不一樣的軟硬件環境下,它的性能是各不相同的。

指令

爲了獲取這些性能的數據,咱們可使用如下指令來獲取數據。

Redis 的最小、最大、平均訪問延遲

redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1

窺探redis爲什麼會變慢

60 秒內的最大響應延遲

redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60

窺探redis爲什麼會變慢

測試步驟

  1. 在相同配置的服務器上,測試一個正常 Redis 實例的基準性能
  2. 找到你認爲可能變慢的 Redis 實例,測試這個實例的基準性能
  3. 若是你觀察到,這個實例的運行延遲是正常 Redis 基準性能的 2 倍以上,便可認爲這個 Redis 實例確實變慢了

發現問題

  1. 業務服務器到 Redis 服務器之間的網絡存在問題,例如網絡線路質量不佳,網絡數據包在傳輸時存在延遲、丟包等狀況
  2. Redis 自己存在問題,須要進一步排查是什麼緣由致使 Redis 變慢

分析問題

分析問題的三把斧,鏈路追蹤,看日誌,大膽猜想

鏈路追蹤

這裏的鏈路追蹤可能有點離題,由於是從整個系統全組件中,進行鏈路質量追蹤,在這個過程當中能夠發現某個環節出現時延太高的現象。常見的工具好比OpenTracing

看日誌

目的是想知道在什麼時間點,執行了哪些命令比較耗時,這個也是有指令來執行的。

Redis 的慢日誌slowlog

查看Redis慢日誌以前,你須要設置慢日誌的閾值,讓redis知道何時就是慢。例如,設置慢日誌的閾值爲 5 毫秒,而且保留最近 500 條慢日誌記錄

只記錄一個命令真正操做內存數據的耗時

# 命令執行耗時超過 5 毫秒,記錄慢日誌
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近 500 條慢日誌
CONFIG SET slowlog-max-len 500

大膽猜想

這些其實都是日常積累到的狀況,也是相關指令自己的問題致使的慢現象。

常用 O(N) 以上覆雜度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合類命令

Redis 在操做內存數據時,時間複雜度太高,要花費更多的 CPU 資源。

所以對於數據的聚合操做,放在客戶端作,也就是帶着強計算能力的終端,redis本質是前端數據到後端數據過渡用的中間件,計算本不是他的強項,過分使用O(n)級別的指令,會致使redis消耗大量的cpu,所以儘可能把相關的開銷負載到強cpu 的終端上。

使用 O(N) 複雜度的命令,但 N 的值很是大

Redis 一次須要返回給客戶端的數據過多,更多時間花費在數據協議的組裝和網絡傳輸過程當中,爲了不這種現象,應該須要避免大數據的傳輸,大象流改老鼠流。執行O(N) 命令,保證N 儘可能的小(推薦N <= 300),每次獲取儘可能少的數據,讓 Redis 能夠及時處理返回

操做bigkey

若是一個key 寫入的value 很是大,那麼 Redis 在分配內存時就會比較耗時。一樣的,當刪除這個key 時,釋放內存也會比較耗時,這種類型的key 咱們通常稱之爲bigkey

指令
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

窺探redis爲什麼會變慢

  1. 對線上實例進行 bigkey 掃描時,Redis 的 OPS 會突增,爲了下降掃描過程當中對 Redis 的影響,最好控制一下掃描的頻率,指定 -i 參數便可,它表示掃描過程當中每次掃描後休息的時間間隔,單位是秒
  2. 掃描結果中,對於容器類型(List、Hash、Set、ZSet)的 key,只能掃描出元素最多的 key。但一個 key 的元素多,不必定表示佔用內存也多,你還須要根據業務狀況,進一步評估內存佔用狀況
優化
  1. 業務應用盡可能避免寫入 bigkey
  2. 若是你使用的 Redis 是 4.0 以上版本,用 UNLINK 命令替代 DEL,此命令能夠把釋放 key 內存的操做,放到後臺線程中去執行,從而下降對 Redis 的影響
  3. 若是你使用的 Redis 是 6.0 以上版本,能夠開啓 lazy-free 機制(lazyfree-lazy-user-del = yes),在執行 DEL 命令時,釋放內存也會放到後臺線程中執行

集中過時,redis雪崩的現象

變慢的時間點頗有規律,例如某個整點,或者每間隔多久就會發生一波延遲

參考資料

  1. https://redis.io/topics/introduction
  2. https://www.runoob.com/redis/redis-data-types.html
  3. https://zhuanlan.zhihu.com/p/58358264
  4. https://medium.com/rahasak/kafka-with-etcd3-d04f438aa639
  5. https://www.jianshu.com/p/a036405f989c
  6. https://tianbin.org/learning/HyperLogLog/
  7. https://juejin.cn/post/6844903791590916109
  8. https://juejin.cn/post/684490386207200052
相關文章
相關標籤/搜索