溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

redis 內(nèi)存優(yōu)化

發(fā)布時間:2020-07-04 13:12:40 來源:網(wǎng)絡(luò) 閱讀:306 作者:jinjiang2009 欄目:開發(fā)技術(shù)

最近做的一個系統(tǒng)大量使用redis,我們將大量的用戶信息存放在redis中,內(nèi)存一申請就是幾百G,體量也是相當(dāng)龐大。所以我們也在不斷的想方法優(yōu)化減少redis的內(nèi)存使用,把我們的優(yōu)化實踐也分享出來。

采用Hash代替<K,V>鍵值對存儲

因為是存放用戶維度的數(shù)據(jù),用戶id(uid)往往會作為key,而一個用戶會有多個信息,比如年齡,生日等等,比較容易想到的存儲結(jié)構(gòu)會采用Hash,將一個用戶的多個信息作為hash里的不同field來存放

善用Hash,List,ZSet的ziplist壓縮特性

Redis針對Hash,List,ZSet都實現(xiàn)了ziplist的壓縮存儲,可以通過配置最大元素不超過512,每個元素大小不超過64bytes,來判斷是否要采用 !ziplist壓縮格式 存儲。

注意:雖然這個ziplist是否啟用做成了配置參數(shù),但對這個配置參數(shù)的修改要謹(jǐn)慎,因為ziplist是一個連續(xù)的數(shù)組空間,查找效率不是O(1)的,如果設(shè)置元素超過512太多,可能導(dǎo)致查找效率降低,反而影響性能。那為什么Redis會采用512*64bytes這樣的默認(rèn)配置呢?據(jù)說是這個大小可以被加載進(jìn)CPU的Cache里,所以即使不是O(1),查找效率也是很快的。

優(yōu)先使用數(shù)字類型,比String類型省空間

在Redis的內(nèi)部,不管是數(shù)字類型,String類型,都會統(tǒng)一用一個叫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就搞定的,還有很多附加的屬性,比如引用計數(shù)(內(nèi)存回收)refcount,lru清理等信息。

但如果使用了上面提到的ziplist,redis對ziplist里元素做了裁剪,讓數(shù)據(jù)更緊湊,所以針對數(shù)字,做了一些特別處理:

* |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,針對大小不同的數(shù)字,分別采用不一樣的內(nèi)存空間來存儲,比如0-127就是2個字節(jié),128-32768就是4個字節(jié)等等。所以算下來,和String相比,大部分情況下更省內(nèi)存。

另外,如果不是采用ziplist的存儲方式,而是直接用redisObject這樣相對龐大的對象存儲呢?

如果能用數(shù)字,還是盡量使用數(shù)字類型,并且是小于10000的數(shù)字最好,因為:

#define OBJ_SHARED_INTEGERS 10000

redis考慮到redisObject這個龐大的對象占用過多內(nèi)存的因素,將10000以下數(shù)字的redisObject做了一個對象池,其他地方都通過指針(4/8bytes)引用這個池里的redisObject,而不是各自存一份。

注: 以上都是針對Redis 3.2之前版本的分析,因為Redis 3.2對內(nèi)存優(yōu)化這部分做了很多改進(jìn),具體的改進(jìn)點還未了解清楚。

最后,對堅持看完的同學(xué)送上一個非常有用的Redis內(nèi)存分析工具: redis-rdb-tools,結(jié)合bgsave的dump文件,分析redis里的數(shù)據(jù),可以看到底層存儲是用的什么數(shù)據(jù)結(jié)構(gòu),占用了多少空間等信息。


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI