原文出處:Java 技術驛站 『chenssy』算法
咱們知道 Redis 的全部數據都存儲在內存中,內存是咱們系統中的一個很是珍貴的資源,不能隨意浪費,因此如何合理高效地利用 Redis 內存就變得很是重要了。本文從兩個方面來闡述 Redis 的內存機制:數據庫
- 知道 Redis 的內存主要消耗在什麼地方
- 如何管理內存
查看內存
在文章[【死磕 Redis】----- info 命令詳解]()介紹了 info memory
命令能夠查看 Redis 內存消耗狀況,是咱們分析 Redis 內存使用狀況的好工具。執行命令後以下:安全
咱們重點關注幾個指標:服務器
屬性名 | 屬性說明 |
---|---|
used_memory |
Redis 分配器分配的內存總量,指 Redis 存儲的全部數據所佔的內存 |
used_memory_human |
以可讀的形式返回 user_memory |
used_memory_rss |
Redis 進程佔用的物理內存總量 |
used_memory_peak |
used_memory 使用的峯值 |
used_memory_peak_human |
可讀格式返回 used_memory_peak |
used_memory_lua |
Lua 引擎消耗的內存大小 |
mem_fragmentation_ratio |
used_memory_rss/used_memory 比值,內存碎片率 |
mem_allocator |
Redis 所使用的內存分配器,默認 jemalloc |
這裏咱們須要重點關注app
mem_fragmentation_ratio > 1
說明多出來的部分名沒有用於數據存儲,而是被內存碎片所消耗,相差越大,說明內存碎片率越嚴重。mem_fragmentation_ratio < 1
通常出如今Redis內存交換(Swap)到硬盤致使(used_memory > 可用最大內存時
,Redis會把舊的和不適用的數據寫入到硬盤,這塊空間就叫Swap空間),出現這種狀況須要格外關注,硬盤速度遠遠慢於內存,Redis性能就會變得不好,甚至僵死。 在理想狀況下mem_fragmentation_ratio
只會比 1 稍微大一點點,也就是 used_memory_rss 的值應該只比 used_memory 稍微高一些。運維
內存消耗劃分
Redis 的內存主要包括:對象內存 + 緩衝內存 + 自身內存 + 內存碎片。以下dom
對象內存工具
對象內存是 Redis 內存中佔用最大的一塊,存儲着全部的用戶數據。咱們知道 Redis 是一個 key-value 的內存數據庫,全部的數據都採用 key-value 型數據類型,每次在建立 key-value 鍵值對對象的時候都要建立兩個對象:key 對象和value 對象。其中 key 對象是字符串,value 對象咱們知道有五中數據類型-String、Hash、List、Set、Zset,每種數據類型在使用的時候佔用的內存不一樣。性能
緩衝內存lua
主要包括:客戶端緩衝、AOF 緩衝區、複製積壓緩衝區。
- 客戶端緩衝:普通的客戶端鏈接
- AOF 緩衝區:Redis 持久化分爲兩種:RDB 和 AOF,其中 RDB 是內存快照,AOF 是將 Redis 的命令 append 在文件中,不過在寫入文件以前會先寫入到緩衝區,而後根據不一樣的持久化策略向磁盤進行同步。在進行 AOF 重寫時也有一個AOF 重寫緩衝區。通常 AOF 緩衝區都會比較小。
- 複製積壓緩衝區:主要用於主從同步。在進行主從同步時,Redis 會將最新的命令寫入到複製積壓緩衝區,在進行復制的時候,會校驗複製偏移量是否在複製積壓緩衝區中,若是是則進行部分複製,不然進行全量複製。它默認狀況下是 1MB,咱們須要根據實際請求適當調整他的大小,畢竟設置過小的話,可能會使部分複製退化爲全量複製。
自身內存
自身內存主要指 AOF/RDB 的時候 Redis 建立子進程內存的消耗,通常這部分的消耗會比較小。
內存碎片
目前可選的分配器有 jemalloc、glibc、tcmalloc,默認 jemalloc。
出現高內存碎片問題的狀況:大量的更新操做,好比 append、setrange;大量的過時鍵刪除,釋放的空間沒法獲得有效利用。
解決辦法:數據對齊,安全重啓(高可用/主從切換)。
內存管理
設置 maxmemory
若是咱們不設置 maxmemory ,Redis 則默認使用無限內存,因此爲了 Redis 不繫統的內存耗盡,咱們在使用 Redis 的時候儘可能去配置 maxmemory,給 Redis 設置內存使用上限。maxmemory 配置的是 Redis 的實際使用內存,即 used_memory,可是因爲有內存碎片的存在,因此 Redis 實際使用的內存會比 used_memory 要大,在合理狀況下通常只會大一點點。
配置內存回收策略
Redis 回收內存大體有兩種機制:
- 刪除達到過時時間的對象
- 當內存達到 maxmemory 時觸發內存溢出控制策略,強制刪除選擇出來的對象
Redis 刪除過時鍵值對對象通常有兩種策略:惰性刪除和主動定時任務刪除。
惰性刪除:這種刪除策略,Redis 不會主動去刪除已通過期的鍵值對,而是等待客戶端去讀取帶有超時屬性的鍵時,若是已經超時了則刪除該鍵值對對象,而後返回空。這樣有一個好處就是節省了 CPU ,由於 Redis 不須要單獨去維護 TTL 鏈表來處理過時鍵的刪除,可是有一個壞處就是若是過時的鍵一直都沒有被訪問,則永遠不會被刪除了。那麼怎麼解決呢?Redis 提供了一個定時任務的刪除機制來補救。
定時任務刪除:Redis 內部維護一個定時任務,默認是每秒運行 10 次,刪除邏輯以下圖:
內存溢出控制策略
當 Redis 所用內存達到 maxmemory 上限時會觸發相應的溢出控制策略。Redis支持6種策略,以下所示:
策略 | 說明 |
---|---|
noeviction | 默認策略,不會刪除任何數據,拒絕全部寫入操做並返 回客戶端錯誤信息(error)OOM command not allowed when used memory,此 時Redis只響應讀操做。 |
volatile-lru | 根據LRU算法刪除設置了超時屬性(expire)的鍵,直 到騰出足夠空間爲止。若是沒有可刪除的鍵對象,回退到noeviction策略。 |
allkeys-lru | 根據LRU算法刪除鍵,無論數據有沒有設置超時屬性, 直到騰出足夠空間爲止。 |
allkeys-random | 隨機刪除全部鍵,直到騰出足夠空間爲止。 |
volatile-random | 隨機刪除過時鍵,直到騰出足夠空間爲止。 |
volatile-ttl | 根據鍵值對象的ttl屬性,刪除最近將要過時數據。若是沒有,回退到noeviction策略。 |
內存溢出控制策略能夠使用 config set maxmemory-policy {policy}
語句進行動態配置。
當 Redis 由於內存溢出刪除鍵時,能夠經過執行 info stats
命令查看 evicted_keys
指標找出當前 Redis 服務器已剔除的鍵數量。
參考
- 《Redis 開發與運維》
- 理解Redis的內存