一、采坑背景
在最大數據分析的過程中,redis是被當做熱數據的緩存庫使用的,在某一天中,redis數據庫熱數據無法插入,此時數據量大概在100萬左右,很是糾結,為什么不能插入?程序的錯誤,不可能,沒有異常。redis插入數據超時,查看正常。難道是redis的配置問題,試着尋找解決方案,在網上找到了不少類似的問題,今天我們就踩一下!
二、探索問題
(一)、redis內存異常
1、我們這里模擬一下當時異常的redis環境,現在數據庫中有27條數據,大概內存占用2.4M左右,我們先把最大內存刻意設置到2M
2、現在我們插入新的數據到redis當中
3、查看數據總數,依舊是27條,是不是很奇怪
(二)、redis內存恢復正常
1、現在我們將redis的內存設置到,大於現在已經使用的內存,問題即可解決
2、重新插入數據
3、數據插入后,顯示情況
到此為止,問題解決,我們是不是還有好多疑問,為什么這樣就OK了?不要急,接下來給大家分析一下!
三、內存消耗
大家都知道Redis的所有的數據都是存在了內存中的,當最大內存不足以滿足現狀的情況下,就會出現數據插入異常的情況!,如何查看Redis中內存的消耗情況哪?可以通過 info memory命令,查看Redis內存消耗的相關指標,從而有助於更好的分析內存。執行命令之后有這么幾個重要的指標:
used_memory:2515680 used_memory_human:2.40M used_memory_rss:2478768 used_memory_rss_human:2.36M used_memory_peak:360040528 used_memory_peak_human:343.36M total_system_memory:0 total_system_memory_human:0B used_memory_lua:39936 used_memory_lua_human:39.00K maxmemory:5000000 maxmemory_human:4.77M maxmemory_policy:noeviction mem_fragmentation_ratio:0.99 mem_allocator:jemalloc-3.6.0
重點需要關注下mem_fragmentation_ratio這個值:
mem_fragmentation_ratio > 1 說明多出來的部分名沒有用於數據存儲,而是被內存碎片所消耗,相差越大,說明內存碎片率越嚴重。
mem_fragmentation_ratio < 1 一般出現在Redis內存交換(Swap)到硬盤導致(used_memory > 可用最大內存時,Redis會把舊的和不適用的數據寫入到硬盤,這塊空間就叫Swap空間),出現這種情況需要格外關注,硬盤速度遠遠慢於內存,Redis性能就會變得很差,甚至僵死。
(一)、內存消耗的划分
Redis的內存主要包括:對象內存+緩沖內存+自身內存+內存碎片。
這里寫圖片描述
1、對象內存
對象內存是Redis內存中占用最大一塊,存儲着所有的用戶的數據。Redis所有的數據都采用的是key-value型數據類型,每次創建鍵值對的時候,都要創建兩個對象,key對象和value對象。key對象都是字符串,value對象的存儲方式,五種數據類型–String,List,Hash,Set,Zset。每種存儲方式在使用的時候長度、數據類型不同,則占用的內存就不同。
2、緩沖內存
主要包括:客戶端緩沖、復制積壓緩沖區、AOF緩沖區
客戶端緩沖:普通的客戶端的連接(大量連接),從客戶端(主要是復制的時候,異地跨機房,或者主節點下有多個從節點),訂閱客戶端(發布訂閱功能,生產大於消費就會造成積壓)
復制積壓緩沖:2.8版本之后提供的可重用的固定大小緩沖區用於實現部分復制功能,默認1MB,主要是在主從同步時用到。
AOF緩沖區:持久化用的,會先寫入到緩沖區,然后根據響應的策略向磁盤進行同步,消耗的內存取決於寫入的命令量和重寫時間,通常很小。
3、內存碎片
目前可選的分配器有jemalloc、glibc、tcmalloc默認jemalloc
出現高內存碎片問題的情況:大量的更新操作,比如append、setrange;大量的過期鍵刪除,釋放的空間無法得到有效利用
解決辦法:數據對齊,安全重啟(高可用/主從切換)。
4、自身內存
主要指AOF/RDB重寫時Redis創建的子進程內存的消耗,Linux具有寫時復制技術(copy-on-write),父子進程會共享相同的物理內存頁,當父進程寫請求時會對需要修改的頁復制出一份副本來完成寫操作。
四、管理內存
(一)設置上限
Redis默認是無限使用內存。所以在使用的時候盡量的去配置maxmemory,給Redis設置內存使用上限,防止因Redis的無限使用造成系統內存耗盡。有一點需要注意的是maxmemory配置的是Redis實際使用的內存量,即used_memory,由於有內存碎片的存在,所以實際的內存使用比used_memory要大。
Redis可以動態的執行內存的調整:
config set maxmemory 6GB
(二)配置內存回收策略
Redis的內存回收機制主要體現在兩個方面上:
對過期數據的處理
當內存使用情況達到maxmemory時觸發內存回收策略
1. 過期鍵的刪除
惰性刪除:什么時候執行呢?就是在客戶端讀取帶有超時屬性的鍵時,如果已經超過鍵值設置的過期時間,則刪除並返回空。這樣做的目的主要是為了節省CPU成本考慮,不需要單獨維護TTL鏈表來處理過期鍵的刪除。但是,如果單獨使用這種方式存在一個問題,如果當前的鍵值永遠不再被訪問呢?就不刪除了嗎?那肯定不行,這就會造成內存泄漏的問題。那Redis是怎么解決的呢?Redis提供了一個定時任務的刪除機制來做補充。
2. 定時任務刪除
Redis內部維護了一個定時任務,默認是每秒運行十次。刪除的邏輯如下圖:
這里寫圖片描述
3.內存溢出控制策略
當Redis使用的內存達到上限maxmemory后,就會根據maxmemory-policy設置的相關策略進行對應的操作,Redis支持一下6中策略: