在使用Memcached的時(shí)候,大部分人可能很少關(guān)注內(nèi)存利用率,因?yàn)镃ache畢竟是Cache,那么對(duì)于存儲(chǔ)數(shù)據(jù)的可靠性要求就不高,丟了也不心疼,總之能夠從DB中Reload回來(lái)即可,話是不錯(cuò)!但是在我們的項(xiàng)目中,卻遇到了一個(gè)棘手的問(wèn)題,就是希望數(shù)據(jù)能夠被Memcached 100%的Cache起來(lái),那么如何讓容量規(guī)劃做到位呢,加多大內(nèi)存才是合理的,問(wèn)題就隨之而來(lái)了!在我們的測(cè)試過(guò)程中,想要放入20G的數(shù)據(jù)(5000萬(wàn))到開(kāi)了25G的Memcached中,本想是沒(méi)有問(wèn)題的,結(jié)果才放到45%的容量的時(shí)候,數(shù)據(jù)就發(fā)生了“Evict”的現(xiàn)象,后續(xù)再繼續(xù)追加數(shù)據(jù),直到全部加完,Memcached的利用率始終維持在50%左右,丟了40%左右的數(shù)據(jù),難道說(shuō)需要開(kāi)個(gè)50G的Memcached才能搞定20G的數(shù)據(jù)存儲(chǔ)?這個(gè)也是不確定的,資源浪費(fèi)太嚴(yán)重了,所以我們就開(kāi)始著手分析原因了,目的就為兩點(diǎn):
① 100%將數(shù)據(jù)Cache起來(lái)
② 提高M(jìn)emcached的內(nèi)存利用率,節(jié)省不必要的成本,將利用率穩(wěn)定在一定合理值,這樣便于將來(lái)我們預(yù)警容量問(wèn)題,也能做好容量規(guī)劃
1、 首先:我們需要了解Memcached的內(nèi)存分配機(jī)制:
Memcached采用了Slab Allocation機(jī)制,這種機(jī)制的好處是預(yù)先分配好內(nèi)存,無(wú)需在使用時(shí)Malloc和Free,解決了內(nèi)存碎片問(wèn)題,分配好的內(nèi)存也可以重復(fù)使用,所以可以減輕內(nèi)存管理的負(fù)擔(dān)。
分配過(guò)程:先初始化若干個(gè)Slab,為每個(gè)Slab分配一個(gè)Page的內(nèi)存空間,Page缺省為1MB,每個(gè)Page根據(jù)Slab規(guī)格被劃分為若干個(gè)相同Size的Chunk,每個(gè)Chunk里保存一個(gè)Item,每個(gè)Item同時(shí)包含了Item結(jié)構(gòu)體、k和V,相同Size的Chunk合成一組Slab Class,如圖例:
我們可以使用Growth Factord對(duì)分配策略進(jìn)行調(diào)優(yōu),默認(rèn)值是1.25,Growth Factor的值不同,分配的Chunk的Size就不同,且不同Slab Class中的Chunk數(shù)量也會(huì)不同,根據(jù)需要調(diào)整才是。
n 缺省值F=1.25的情況下,Slab分配情況如下:
slab class 1: chunk size 88 perslab 11915
slab class 2: chunk size 112 perslab 9362
slab class 3: chunk size 144 perslab 7281
slab class 4: chunk size 184 perslab 5698
slab class 5: chunk size 232 perslab 4519
slab class 6: chunk size 296 perslab 3542
slab class 7: chunk size 376 perslab 2788
slab class 8: chunk size 472 perslab 2221
slab class 9: chunk size 592 perslab 1771
slab class 10: chunk size 744 perslab 1409
n 若F=2的情況下,Slab分配情況如下:
slab class 1: chunk size 128 perslab 8192
slab class 2: chunk size 256 perslab 4096
slab class 3: chunk size 512 perslab 2048
slab class 4: chunk size 1024 perslab 1024
slab class 5: chunk size 2048 perslab 512
slab class 6: chunk size 4096 perslab 256
slab class 7: chunk size 8192 perslab 128
slab class 8: chunk size 16384 perslab 64
slab class 9: chunk size 32768 perslab 32
slab class 10: chunk size 65536 perslab 16
2、 其次,了解數(shù)據(jù)存儲(chǔ)的原理:
Memcached在收到需要存儲(chǔ)的數(shù)據(jù)后,先計(jì)算數(shù)據(jù)的Size,最大存入1M的數(shù)據(jù),然后選擇適合的Slab Class中的Chunk(當(dāng)然Memcached會(huì)記錄哪些Chunk是空閑的),,如圖例:
在數(shù)據(jù)存入選中的Slab Class,可能有以下兩種情況:
n 若該Slab Class未滿(free_chunks > 0),則成功存入;
n 若該Slab Class滿了(free_chunks=0),有可能發(fā)生以下兩種情況:
l 有可用內(nèi)存,則新增一個(gè)Page的內(nèi)存給該Slab,該P(yáng)age也是被當(dāng)前Slab的同樣規(guī)格進(jìn)行劃分若干Chunk,然后將數(shù)據(jù)存入新增的Chunk中;
l 無(wú)可用內(nèi)存,有可能發(fā)生以下兩種情況:
u 啟用LRU(LRU的Scope只是針對(duì)Slab的,而非全局),將新數(shù)據(jù)替換老數(shù)據(jù),老數(shù)據(jù)丟失
u 禁用LRU(追加Memcached的啟動(dòng)參數(shù)-M),發(fā)生Out Of Memory錯(cuò)誤
由于分配的都是定長(zhǎng)Chunk,在內(nèi)存利用率上也有天然的缺陷,如圖例:
n 不僅僅存在單個(gè)Chunk上浪費(fèi)現(xiàn)象
n 而且會(huì)存在整個(gè)Slab Class浪費(fèi)的現(xiàn)象,因?yàn)橛袝r(shí)遇到的數(shù)據(jù)Size根本落不到這個(gè)Slab Class上都是可能的
總之,Memcached可謂用心良苦,用空間換取性能,當(dāng)然應(yīng)用在使用時(shí)需要注意到這點(diǎn)特性,才能用好Memcached。
3、 最后,就必須要對(duì)自己應(yīng)用的數(shù)據(jù)Size分布做個(gè)透徹的分析,才能將Memcached物盡其用:
根據(jù)經(jīng)驗(yàn)所得:
n 數(shù)據(jù)Size的分布盡量集中可以提高M(jìn)emcached的內(nèi)存利用率
以我遇到的問(wèn)題做為例: 我們需要在Memcached里保存User的操作記錄,為了貪圖查詢的方便,我們就Key<UserID> = Value<List<操作記錄>>,當(dāng)每位User的操作記錄數(shù)量從1到n都有分布,那么n較大的數(shù)據(jù)就會(huì)選擇了Size較大的Chunk進(jìn)行儲(chǔ)存,若出現(xiàn)17193bytes大小的數(shù)據(jù),那么只能從以下兩個(gè)Slab中選擇Slab Class 25進(jìn)行存儲(chǔ):
slab class 24: chunk size 17192 perslab 60
slab class 25: chunk size 21496 perslab 48
如果這樣Size的數(shù)據(jù)非常多的話,那就非常杯具了,浪費(fèi)的內(nèi)存成(21496-17193)*m線性增長(zhǎng);因此我們改變了存儲(chǔ)策略,使用Key<操作記錄ID> = Value<操作記錄>, Key<UserId> = Value<List<操作記錄 ID>>進(jìn)行存儲(chǔ),這樣操作記錄的每對(duì)K/V的Size都在200bytes左右,結(jié)果內(nèi)存利用了提升到90%左右;
n 根據(jù)Value的Size分布,適當(dāng)調(diào)整的Growth Factor也是可以提升內(nèi)存利用率
n 最后,Memcached本身就是解決不可靠數(shù)據(jù)的存取服務(wù)的,做為二級(jí)緩存是不錯(cuò)的選擇,可以很大程度的提升性能,但是要想存取可靠的數(shù)據(jù),就不能選擇Memcached,選擇一項(xiàng)“適合的”技術(shù)保障可用性才是王道。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
