1. 程式人生 > >redis調優的實戰經驗

redis調優的實戰經驗

href 官方文檔 hash結構 volatile memory 占用 簡單 可用內存 公眾

本文根據redis的info命令查看redis的內存使用情況以及state狀態,來觀察redis的運行情況以及需要作出的相應優化。

info

1.memory
used_memory:13409011624 #used_memory=實際緩存占用的內存+Redis自身運行所占用的內存(如元數據、lua)。
                        #這個值是由Redis使用內存分配器分配的內存,不包括內存碎片浪費的內存。
used_memory_rss:13740019719  #從操作系統上顯示已經分配的內存總量。
used_memory_peak:13409011624  #內存使用的峰值大小
total_system_memory:33567678464  #系統總內存
used_memory_lua:37888  #Lua腳本引擎所使用的內存大小。
maxmemory:0  #最大可用內存(可配置,默認為total_system_memory)
maxmemory_policy:noeviction  #淘汰機制,noneviction為禁止淘汰數據
mem_fragmentation_ratio:1.02;  #內存碎片率
mem_allocator:jemalloc-4.0.3; #編譯時指定的Redis內存分配器,可以是libc、jemalloc、tcmalloc。

2.stats
total_commands_processed:3500  #自啟動起Redis服務處理命令的總數

1.used_memory 過大導致的問題

1.1.引發內存交換

??當Redis內存使用率超過可用內存(maxmemory可配置)的95%時,操作系統會進行內存與swap空間數據交換。把內存中舊的或不再使用的內容寫入硬盤上即Swap分區,以便騰出新的物理內存給新頁或活動頁(page)使用。 在硬盤上進行讀寫操作要比在內存上進行讀寫操作,時間上慢了近5個數量級,內存是0.1μs單位、而硬盤是10ms。如果Redis進程上發生內存交換,那麽Redis和依賴Redis上數據的應用會受到嚴重的性能影響。

1.2.rdb持久化風險

??在沒有開啟持久化的情況下,redis宕機或者內存使用率超過95%會有丟數據的風險

。若使用快照(rdb)持久化,Redis會fork一個子進程把當前內存中的數據完全復制一份寫入到硬盤上(fork使用的內存和redis當前使用的內存會一樣多)。因此若是當前使用內存超過可用內存的45%時觸發快照功能,那麽此時進行的內存交換會變的非常危險(可能會丟失數據)。 倘若在這個時候實例上有大量頻繁的更新操作,問題會變得更加嚴重。

2.避免used_memory 過大

  • 盡可能的使用Hash數據結構

??因為Redis在儲存小於100個字段的Hash結構上,其存儲效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的時候,盡可能的使用Hash結構。比如,在一個web應用程序中,需要存儲一個對象表示用戶信息,使用單個key表示一個用戶,其每個屬性存儲在Hash的字段裏,這樣要比給每個屬性單獨設置一個key-value要高效的多。 通常情況下倘若有數據使用string結構,用多個key存儲時,那麽應該轉換成單key多字段的Hash結構。 如上述例子中介紹的Hash結構應包含,單個對象的屬性或者單個用戶各種各樣的資料。Hash結構的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存儲或從Hash中取出指定的字段。

  • 設置key的過期時間

??一個減少內存使用率的簡單方法就是,每當存儲對象時確保設置key的過期時間。倘若key在明確的時間周期內使用或者舊key不大可能被使用時,就可以用Redis過期時間命令(expire,expireat, pexpire, pexpireat)去設置過期時間,這樣Redis會在key過期時自動刪除key。 假如你知道每秒鐘有多少個新key-value被創建,那可以調整key的存活時間,並指定閥值去限制Redis使用的最大內存。

  • 回收key

??在Redis配置文件Redis.conf中,通過設置“maxmemory”屬性的值可以限制Redis最大使用的內存,修改後重啟實例生效。 也可以使用客戶端命令config set maxmemory 去修改值,這個命令是立即生效的,但會在重啟後會失效,需要使用config rewrite命令去刷新配置文件。

  1. 若是啟用了Redis快照功能,應該設置“maxmemory”值為系統可使用內存的45%,因為快照時需要一倍的內存來復制整個數據集,也就是說如果當前已使用45%,在快照期間會變成95%(45%+45%+5%),其中5%是預留給其他的開銷。
  2. 如果沒開啟快照功能,maxmemory最高能設置為系統可用內存的95%。
  • 淘汰策略

??當內存使用達到設置的最大閥值時,需要選擇一種key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”屬性值。 若是Redis數據集中的key都設置了過期時間,那麽“volatile-ttl”策略是比較好的選擇。但如果key在達到最大內存限制時沒能夠迅速過期,或者根本沒有設置過期時間。那麽設置為“allkeys-lru”值比較合適,它允許Redis從整個數據集中挑選最近最少使用的key進行刪除(LRU淘汰算法)。

Redis還提供了一些其他淘汰策略,如下:

volatile-lru:使用LRU算法從已設置過期時間的數據集合中淘汰數據。
volatile-ttl:從已設置過期時間的數據集合中挑選即將過期的數據淘汰。
volatile-random:從已設置過期時間的數據集合中隨機挑選數據淘汰。
allkeys-lru:使用LRU算法從所有數據集合中淘汰數據。
allkeys-random:從數據集合中任意選擇數據淘汰
no-enviction:禁止淘汰數據。

??通過設置maxmemory為系統可用內存的45%或95%(取決於持久化策略)和設置“maxmemory-policy”為“volatile-ttl”或“allkeys-lru”(取決於過期設置),可以比較準確的限制Redis最大內存使用率,在絕大多數場景下使用這2種方式可確保Redis不會進行內存交換。倘若你擔心由於限制了內存使用率導致丟失數據的話,可以設置noneviction值禁止淘汰數據。

3. used_memory_rss 過大解決辦法

??當mem_fragmentation_ratio遠大於1時即used_memory_rss/used_memory(稍大於1正常),說明redis中存在大量的內存碎片,一個比較好的解決辦法就是重啟redis,這裏需要註意的是如果用的是aof持久化,那麽重啟之前要進行rewriteaof操作,否則會無效。還有可以指定Redis使用的內存分配器,一般管理員不推薦,麻煩而且要重新編譯。

參考:

  1. redis官方文檔
  2. 不錯的英文文檔

評論不能及時回復可直接加公眾號提問或交流,知無不答,謝謝 。
技術分享圖片

redis調優的實戰經驗