Redis 記憶體優化

2021-07-26 19:20:55 字數 2662 閱讀 2295

非常感謝

redis內部有很多的資料型別,這些在官方文件上都可以看到,下面是其內部優化的一些細節點:

1. string 和 數字,在redis中如果儲存的是「123」redis是能夠識別出來這是乙個數字並且按照數字來儲存,節省儲存空間,當然除了這個優化之外,redis內部會構建乙個數字池,預設是10000,那麼如果是在這個池子的數字就只需要用乙個簡單的索引來引用進來就可以,而不需要把重複的數字都分開儲存。這個數值可以調整源**的巨集:redis_shared_integers來擴大和縮小池子的大小。

2.複雜型別的儲存優化,比如map,list,set等,這些集合都有乙個特點可大可小,根據實際場景來定,一般情況下如果這些集合所包含的entry不多,並且每個entry所包含的value不是很長的情況下,redis內部使用緊湊格式來儲存資料,緊湊格式儲存資料在查詢場景的演算法複雜度是o(n),而類似map或者set他們的查詢演算法複雜度都是o(1)那為什麼要這麼做呢 ?為了能夠節省記憶體空間,在n很小的時候其實和o(1)沒什麼區別。所以這裡不的不介紹緊湊格式的代表zipmap,

可以看出,這個結構中初始情況只有2個位元組,隨著操作的增加它會變長,其中最關鍵的是乙個關於free這個欄位的理解,以map為例,如果新插入乙個key,那麼對應zipmap就會多出來一長串資料:。從圖中可以看到插入key1的時候只有綠色的一串,當key2插入的時候就會又出來乙個類似的黃色結構串。free的功能是在插入的時候用來冗餘空間的,當key所對應的數值發生變化的時候,如果資料變的比之前短了,那麼free的長度就變大,這個時候不需要做zipmap的resize操作,如果資料長度變長了,並且在free能夠足以支援新資料的範圍之內,那麼free就被利用起來,並且也不需要做resize。這個時候會有空間的浪費或者說碎片。空間換時間吧,沒什麼好說的。當然redis的**中還有另外乙個引數zipmap_value_max_free,這個引數可以用來設定如果free的大小超過了這個值,那麼zipmap會發生resize(收縮),從而節約空間。

常用記憶體優化手段與引數

redis實際上的記憶體管理成本非常高,即占用了過多的記憶體,作者對這點也非常清楚,所以提供了一系列的引數和手段來控制和節省記憶體,我們分別來討論下。

1.首先最重要的一點是不要開啟redis的vm選項,即虛擬記憶體功能,這個本來是作為redis儲存超出物理記憶體資料的一種資料在記憶體與磁碟換入換出的乙個持久化策略,但是其記憶體管理成本也非常的高,並且我們後續會分析此種持久化策略並不成熟,所以要關閉vm功能,請檢查你的redis.conf檔案中 vm-enabled 為 no。

2.其次最好設定下redis.conf中的maxmemory選項,該選項是告訴redis當使用了多少物理記憶體後就開始拒絕後續的寫入請求,該引數能很好的保護好你的redis不會因為使用了過多的物理記憶體而導致swap,最終嚴重影響效能甚至崩潰。

3.另外redis為不同資料型別分別提供了一組引數來控制記憶體使用,我們在前面詳細分析過redis hash是value內部為乙個hashmap,如果該map的成員數比較少,則會採用類似一維線性的緊湊格式來儲存該map, 即省去了大量指標的記憶體開銷,這個引數控制對應在redis.conf配置檔案中下面2項:

hash-max-zipmap-entries 64 

hash-max-zipmap-value 512 

hash-max-zipmap-entries

含義是當value這個map內部不超過多少個成員時會採用線性緊湊格式儲存,預設是64,即value內部有64個以下的成員就是使用線性緊湊儲存,超過該值自動轉成真正的hashmap。

hash-max-zipmap-value 含義是當 value這個map內部的每個成員值長度不超過多少位元組就會採用線性緊湊儲存來節省空間。

以上2個條件任意乙個條件超過設定值都會轉換成真正的hashmap,也就不會再節省記憶體了,那麼這個值是不是設定的越大越好呢,答案當然是否定的,hashmap的優勢就是查詢和操作的時間複雜度都是o(1)的,而放棄hash採用一維儲存則是o(n)的時間複雜度,如果成員數量很少,則影響不大,否則會嚴重影響效能,所以要權衡好這個值的設定,總體上還是最根本的時間成本和空間成本上的權衡。

同樣類似的引數還有:

list-max-ziplist-entries 512

說明:list資料型別多少節點以下會採用去指標的緊湊儲存格式。

list-max-ziplist-value 64 

說明:list資料型別節點值大小小於多少位元組會採用緊湊儲存格式。

set-max-intset-entries 512 

說明:set資料型別內部資料如果全部是數值型,且包含多少節點以下會採用緊湊格式儲存。

最後想說的是redis內部實現沒有對記憶體分配方面做過多的優化,在一定程度上會存在記憶體碎片,不過大多數情況下這個不會成為redis的效能瓶頸,不過如果在redis內部儲存的大部分資料是數值型的話,redis內部採用了乙個shared integer的方式來省去分配記憶體的開銷,即在系統啟動時先分配乙個從1~n 那麼多個數值物件放在乙個池子中,如果儲存的資料恰好是這個數值範圍內的資料,則直接從池子裡取出該物件,並且通過引用計數的方式來共享,這樣在系統儲存了大量數值下,也能一定程度上節省記憶體並且提高效能,這個引數值n的設定需要修改源**中的一行巨集定義redis_shared_integers,該值預設是10000,可以根據自己的需要進行修改,修改後重新編譯就可以了。

參考文章

redis記憶體儲存結構分析:

redis幾個認識誤區:

redis記憶體優化

在資料量小或者只有int資料的時候,redis採用更緊湊的資料結構來儲存資料 zset hash ziplist set int intset 這些特殊的資料結構是一整塊記憶體,避免來記憶體分片,節省了記憶體,並且增加了cache命中,所以雖然演算法複雜度變成了on,但其實更快了 對於只需要flag...

Redis記憶體優化

redis可以當做記憶體使用,但是如果一直往裡儲存不刪除資料,則必然導致記憶體溢位.想法 如何可以實現記憶體資料的維護呢?可以讓使用者永遠都可以存資料.lru是least recently used的縮寫,即最近最少使用,是一種常用的頁面置換演算法,選擇最近最久未使用的頁面予以淘汰。該演算法賦予每個...

Redis筆記 記憶體優化

redis2.2版本及以後,儲存集合資料的時候會採用記憶體壓縮技術,以使用更少的記憶體儲存更多的資料。如hashes,lists,sets和sorted sets,當這些集合中的所有數都小於乙個給定的元素,並且集合中元素數量小於某個值時,儲存的資料會被以一種非常節省記憶體的方式進行編碼,使用這種編碼...