【死磕 Redis】—— 理解 Redis 的內存

原文出處:Java 技術驛站chenssy算法


咱們知道 Redis 的全部數據都存儲在內存中,內存是咱們系統中的一個很是珍貴的資源,不能隨意浪費,因此如何合理高效地利用 Redis 內存就變得很是重要了。本文從兩個方面來闡述 Redis 的內存機制:數據庫

  1. 知道 Redis 的內存主要消耗在什麼地方
  2. 如何管理內存

查看內存

在文章[【死磕 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 回收內存大體有兩種機制:

  1. 刪除達到過時時間的對象
  2. 當內存達到 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 服務器已剔除的鍵數量。

參考

相關文章
相關標籤/搜索