首先,這個(gè)通過(guò)圖片ID反查用戶UID的應(yīng)用有以下幾點(diǎn)需求:
Instagram的開(kāi)發(fā)者首先否定了數(shù)據(jù)庫(kù)存儲(chǔ)的方案,他們保持了KISS原則(Keep It Simple and Stupid),因?yàn)檫@個(gè)應(yīng)用根本用不到數(shù)據(jù)庫(kù)的update功能,事務(wù)功能和關(guān)聯(lián)查詢等等牛X功能,所以不必為這些用不到的功能去選擇維護(hù)一個(gè)數(shù)據(jù)庫(kù)。
于是他們選擇了Redis,Redis是一個(gè)支持持久化的內(nèi)存數(shù)據(jù)庫(kù),所有的數(shù)據(jù)都被存儲(chǔ)在內(nèi)存中(忘掉VM吧),而最簡(jiǎn)單的實(shí)現(xiàn)就是使用Redis的String結(jié)構(gòu)來(lái)做一個(gè)key-value存儲(chǔ)就行了。像這樣:
SET media:1155315 939GET media:1155315> 939
其中1155315是圖片ID,939是用戶ID,我們將每一張圖片ID為作key,用戶uid作為value來(lái)存成key-value對(duì)。然后他們進(jìn)行了測(cè)試,將數(shù)據(jù)按上面的方法存儲(chǔ),1,000,000數(shù)據(jù)會(huì)用掉70MB內(nèi)存,300,000,000張照片就會(huì)用掉21GB的內(nèi)存。對(duì)比預(yù)算的17GB還是超支了。
(NoSQLFan:其實(shí)這里我們可以看到一個(gè)優(yōu)化點(diǎn),我們可以將key值前面相同的media去掉,只存數(shù)字,這樣key的長(zhǎng)度就減少了,減少key值對(duì)內(nèi)存的開(kāi)銷【注:Redis的key值不會(huì)做字符串到數(shù)字的轉(zhuǎn)換,所以這里節(jié)省的,僅僅是media:這6個(gè)字節(jié)的開(kāi)銷】。經(jīng)過(guò)實(shí)驗(yàn),內(nèi)存占用會(huì)降到50MB,總的內(nèi)存占用是15GB,是滿足需求的,但是Instagram后面的改進(jìn)任然有必要)
于是Instagram的開(kāi)發(fā)者向Redis的開(kāi)發(fā)者之一Pieter Noordhuis詢問(wèn)優(yōu)化方案,得到的回復(fù)是使用Hash結(jié)構(gòu)。具體的做法就是將數(shù)據(jù)分段,每一段使用一個(gè)Hash結(jié)構(gòu)存儲(chǔ),由于Hash結(jié)構(gòu)會(huì)在單個(gè)Hash元素在不足一定數(shù)量時(shí)進(jìn)行壓縮存儲(chǔ),所以可以大量節(jié)約內(nèi)存。這一點(diǎn)在上面的String結(jié)構(gòu)里是不存在的。而這個(gè)一定數(shù)量是由配置文件中的hash-zipmap-max-entries參數(shù)來(lái)控制的。經(jīng)過(guò)開(kāi)發(fā)者們的實(shí)驗(yàn),將hash-zipmap-max-entries設(shè)置為1000時(shí),性能比較好,超過(guò)1000后HSET命令就會(huì)導(dǎo)致CPU消耗變得非常大。
于是他們改變了方案,將數(shù)據(jù)存成如下結(jié)構(gòu):
HSET "mediabucket:1155" "1155315" "939"HGET "mediabucket:1155" "1155315"> "939"
通過(guò)取7位的圖片ID的前四位為Hash結(jié)構(gòu)的key值,保證了每個(gè)Hash內(nèi)部只包含3位的key,也就是1000個(gè)。
再做一次實(shí)驗(yàn),結(jié)果是每1,000,000個(gè)key只消耗了16MB的內(nèi)存??們?nèi)存使用也降到了5GB,滿足了應(yīng)用需求。
(NoSQLFan:同樣的,這里我們還是可以再進(jìn)行優(yōu)化,首先是將Hash結(jié)構(gòu)的key值變成純數(shù)字,這樣key長(zhǎng)度減少了12個(gè)字節(jié),其次是將Hash結(jié)構(gòu)中的subkey值變成三位數(shù),這又減少了4個(gè)字節(jié)的開(kāi)銷,如下所示。經(jīng)過(guò)實(shí)驗(yàn),內(nèi)存占用量會(huì)降到10MB,總內(nèi)存占用為3GB)
HSET "1155" "315" "939"HGET "1155" "315"> "939"
優(yōu)化無(wú)止境,只要肯琢磨。希望你在使用存儲(chǔ)產(chǎn)品時(shí)也能如此愛(ài)惜內(nèi)存。
來(lái)源:instagram-engineering.tumblr.com
聯(lián)系客服