標籤:redis 記憶體空間最佳化
最近做的一個系統大量使用redis,我們將大量的使用者資訊存放在redis中,記憶體一申請就是幾百G,體量也是相當龐大。所以我們也在不斷的想方法最佳化減少redis的記憶體使用量,把我們的最佳化實踐也分享出來。
採用Hash代替<K,V>索引值對儲存
因為是存放使用者維度資料,使用者id(uid)往往會作為key,而一個使用者會有多個資訊,比如年齡,生日等等,比較容易想到的儲存結構會採用Hash,將一個使用者的多個資訊作為hash裡的不同field來存放
善用Hash,List,ZSet的ziplist壓縮特性
Redis針對Hash,List,ZSet都實現了ziplist的壓縮儲存,可以通過配置最大元素不超過512,每個元素大小不超過64bytes,來判斷是否要採用 !ziplist壓縮格式 儲存。
注意:雖然這個ziplist是否啟用做成了配置參數,但對這個配置參數的修改要謹慎,因為ziplist是一個連續的數組空間,尋找效率不是O(1)的,如果設定元素超過512太多,可能導致尋找效率降低,反而影響效能。那為什麼Redis會採用512*64bytes這樣的預設配置呢?據說是這個大小可以被載入進CPU的Cache裡,所以即使不是O(1),尋找效率也是很快的。
優先使用數字類型,比String類型省空間
在Redis的內部,不管是數字類型,String類型,都會統一用一個叫redisObject的對象做一層封裝:
typedef struct redisObject { unsigned type:4; unsigned encoding:4; unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */ int refcount; void *ptr;} robj;
可見,一個簡簡單單的”hello world”在redis裡都不是直接11個bytes就搞定的,還有很多附加的屬性,比如引用計數(記憶體回收)refcount,lru清理等資訊。
但如果使用了上面提到的ziplist,redis對ziplist裡元素做了裁剪,讓資料更緊湊,所以針對數字,做了一些特別處理:
* |11000000| - 1 byte* Integer encoded as int16_t (2 bytes).* |11010000| - 1 byte* Integer encoded as int32_t (4 bytes).* |11100000| - 1 byte* Integer encoded as int64_t (8 bytes).* |11110000| - 1 byte* Integer encoded as 24 bit signed (3 bytes).* |11111110| - 1 byte* Integer encoded as 8 bit signed (1 byte).* |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer.* Unsigned integer from 0 to 12. The encoded value is actually from* 1 to 13 because 0000 and 1111 can not be used, so 1 should be* subtracted from the encoded 4 bit value to obtain the right value.
先用1byte來表示不同的encode,針對大小不同的數字,分別採用不一樣的記憶體空間來儲存,比如0-127就是2個位元組,128-32768就是4個位元組等等。所以算下來,和String相比,大部分情況下更省記憶體。
另外,如果不是採用ziplist的儲存方式,而是直接用redisObject這樣相對龐大的Object Storage Service呢?
如果能用數字,還是盡量使用數字類型,並且是小於10000的數字最好,因為:
#define OBJ_SHARED_INTEGERS 10000
redis考慮到redisObject這個龐大的對象佔用過多記憶體的因素,將10000以下數位redisObject做了一個對象池,其他地方都通過指標(4/8bytes)引用這個池裡的redisObject,而不是各自存一份。
注: 以上都是針對Redis 3.2之前版本的分析,因為Redis 3.2對記憶體最佳化這部分做了很多改進,具體的改進點還未瞭解清楚。
最後,對堅持看完的同學送上一個非常有用的Redis記憶體分析工具: redis-rdb-tools,結合bgsave的dump檔案,分析redis裡的資料,可以看到底層儲存是用的什麼資料結構,佔用了多少空間等資訊。
redis 記憶體最佳化