?????? Memcache存儲(chǔ)大數(shù)據(jù)的問(wèn)題 ? ?? huangguisu
????? Memcached存儲(chǔ)單個(gè)item最大數(shù)據(jù)是在1MB內(nèi),假設(shè)數(shù)據(jù)超過(guò)1M,存取set和get是都是返回false,并且引起性能的問(wèn)題。
我們之前對(duì)排行榜的數(shù)據(jù)進(jìn)行緩存。因?yàn)榕判邪裨谖覀內(nèi)縮ql select查詢(xún)里面占了30%,并且我們排行榜每小時(shí)更新一次,所以必須對(duì)數(shù)據(jù)做緩存。
為了清除緩存方便,把全部的用戶(hù)的數(shù)據(jù)放在同一key中,因?yàn)閙emcached:set的時(shí)候沒(méi)有壓縮數(shù)據(jù)。在測(cè)試服測(cè)試的時(shí)候,沒(méi)發(fā)現(xiàn)問(wèn)題。當(dāng)上線(xiàn)的時(shí)候,結(jié)果發(fā)現(xiàn)。在線(xiàn)人數(shù)剛剛490人的時(shí)候,serverload average飄到7.9。然后我們?nèi)サ艟彺妫幌伦泳拖陆档?.59。
所以Memcahce不適合緩存大數(shù)據(jù),超過(guò) 1MB的數(shù)據(jù) ,能夠考慮在client壓縮或拆分到多個(gè) key 中。大的數(shù)據(jù)在進(jìn)行l(wèi)oad和uppack到內(nèi)存的時(shí)候須要花非常長(zhǎng)時(shí)間,從而減少server的性能。
Memcached 支持最大的存儲(chǔ)對(duì)象為 1M 。這個(gè)值由其內(nèi)存分配機(jī)制決定的。
memcached 默認(rèn)情況下採(cǎi)用了名為 Slab Allocator 的機(jī)制分配、管理內(nèi)存。在該機(jī)制出現(xiàn)曾經(jīng),內(nèi)存的分配是通過(guò)對(duì)全部記錄簡(jiǎn)單地進(jìn)行 malloc 和 free 來(lái)進(jìn)行的。
可是,這樣的方式會(huì)導(dǎo)致內(nèi)存碎片,加重操作系統(tǒng)內(nèi)存管理器的負(fù)擔(dān),最壞的情況下。會(huì)導(dǎo)致操作系統(tǒng)比 memcached 進(jìn)程本身還慢。 Slab Allocator 就是為解決該問(wèn)題而誕生的。
Slab Allocator 的基本原理是依照預(yù)先規(guī)定的大小,將分配的內(nèi)存切割成特定長(zhǎng)度的塊。以全然解決內(nèi)存碎片問(wèn)題.
今天(2012-03-16)我們又一次測(cè)試了memcached ::set的數(shù)據(jù)大小。可能是我們用php的memcached擴(kuò)展是最新版,set數(shù)據(jù)的時(shí)候是默認(rèn)壓縮的。set 數(shù)據(jù):
$ac = new memcahed(); $data = str_repeat('a', 1024* 1024); //1M的數(shù)據(jù) $r = $ac->set('key', $data, 9999); //或者 $data = str_repeat('a', 1024* 1024*100);//100M的數(shù)據(jù) $r = $ac->set('key', $data, 9999);
不論是1M的數(shù)據(jù)還是100M的數(shù)據(jù),都能set成功。
后來(lái)我發(fā)現(xiàn),memcached set數(shù)據(jù)的時(shí)候是默認(rèn)壓縮的。
因?yàn)檫@個(gè)這個(gè)是反復(fù)的字符串,壓縮率高達(dá)1000倍。因此100M的數(shù)據(jù)壓縮后實(shí)際也就100k而已。
當(dāng)我設(shè)置:
$ac->setOption(memcahed::OPT_COMPRESSION,0); //不壓縮存儲(chǔ)數(shù)據(jù)。 $data = str_repeat('a', 1024* 1024); //1M數(shù)據(jù) $r = $ac->set('key', $data, 9999);//1M的數(shù)據(jù)set不成功。
也就是說(shuō)memcached server不能存儲(chǔ)超過(guò)1M的數(shù)據(jù),可是 經(jīng)過(guò) client壓縮數(shù)據(jù)后,僅僅要小于1M的數(shù)據(jù)都能存儲(chǔ)成功。
memcached相關(guān)知識(shí):
1、memcached的基本設(shè)置
1)啟動(dòng)Memcache的server端
# /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 12000 -c 256 -P /tmp/memcached.pid
-d選項(xiàng)是啟動(dòng)一個(gè)守護(hù)進(jìn)程,
-m是分配給Memcache使用的內(nèi)存數(shù)量,單位是MB,我這里是10MB。
-u是執(zhí)行Memcache的用戶(hù)。我這里是root。
-l是監(jiān)聽(tīng)的serverIP地址。假設(shè)有多個(gè)地址的話(huà),我這里指定了server的IP地址192.168.0.200,
-p是設(shè)置Memcache監(jiān)聽(tīng)的port。我這里設(shè)置了12000,最好是1024以上的port,
-c選項(xiàng)是最大執(zhí)行的并發(fā)連接數(shù),默認(rèn)是1024,我這里設(shè)置了256,依照你server的負(fù)載量來(lái)設(shè)定,
-P是設(shè)置保存Memcache的pid文件,我這里是保存在 /tmp/memcached.pid。
2)假設(shè)要結(jié)束Memcache進(jìn)程。運(yùn)行:
# kill `cat /tmp/memcached.pid`
哈希算法 將 隨意長(zhǎng)度的二進(jìn)制值映射為固定長(zhǎng)度的較小二進(jìn)制值。這個(gè)小的二進(jìn)制值稱(chēng)為哈希值。哈希值是一段數(shù)據(jù)唯一且極其緊湊的數(shù)值表示形式。假設(shè)散列一段明文并且哪怕僅僅更改該
段落的一個(gè)字母。隨后的哈希都將產(chǎn)生不同的值。要找到散列為同一個(gè)值的兩個(gè)不同的輸入,在計(jì)算上是不可能的。
2、適用memcached的業(yè)務(wù)場(chǎng)景?
1)假設(shè)站點(diǎn)包括了訪問(wèn)量非常大的動(dòng)態(tài)網(wǎng)頁(yè)。因而數(shù)據(jù)庫(kù)的負(fù)載將會(huì)非常高。因?yàn)榇蟛糠謹(jǐn)?shù)據(jù)庫(kù)請(qǐng)求都是讀操作,那么memcached能夠顯著地減小數(shù)據(jù)庫(kù)負(fù)載。
2)假設(shè)數(shù)據(jù)庫(kù)server的負(fù)載比較低但CPU使用率非常高,這時(shí)能夠緩存計(jì)算好的結(jié)果( computed objects )和渲染后的網(wǎng)頁(yè)模板(enderred templates)。
3)利用memcached能夠緩存 session數(shù)據(jù) 、暫時(shí)數(shù)據(jù)以降低對(duì)他們的數(shù)據(jù)庫(kù)寫(xiě)操作。
4)緩存一些非常小可是被頻繁訪問(wèn)的文件。
5)緩存Web 'services'(非IBM宣揚(yáng)的Web Services,譯者注)或RSS feeds的結(jié)果.。
3、不適用memcached的業(yè)務(wù)場(chǎng)景?
1)緩存對(duì)象的大小大于1MB
Memcached本身就不是為了處理龐大的多媒體(large media)和巨大的二進(jìn)制塊(streaming huge blobs)而設(shè)計(jì)的。
2)key的長(zhǎng)度大于250字符
3)虛擬主機(jī)不讓執(zhí)行memcached服務(wù)
???? 假設(shè)應(yīng)用本身托管在低端的虛擬私有server上。像vmware, xen這類(lèi)虛擬化技術(shù)并不適合執(zhí)行memcached。Memcached須要接管和控制大塊的內(nèi)存。假設(shè)memcached管理 ? ? ?的內(nèi)存被OS或 hypervisor交換出去,memcached的性能將大打折扣。
4)應(yīng)用執(zhí)行在不安全的環(huán)境中
Memcached為提供不論什么安全策略,只通過(guò)telnet就能夠訪問(wèn)到memcached。
假設(shè)應(yīng)用執(zhí)行在共享的系統(tǒng)上,須要著重考慮安全問(wèn)題。
5)業(yè)務(wù)本身須要的是持久化數(shù)據(jù)或者說(shuō)須要的應(yīng)該是database
4、 不能可以遍歷memcached中全部的item
? ? ?這個(gè)操作的速度相對(duì)緩慢且堵塞其它的操作(這里的緩慢時(shí)相比memcached其它的命令)。memcached全部非調(diào)試(non-debug)命令,比如add, set, get, fulsh等不管
memcached中存儲(chǔ)了多少數(shù)據(jù),它們的運(yùn)行都僅僅消耗常量時(shí)間。
不論什么遍歷全部item的命令運(yùn)行所消耗的時(shí)間。將隨著memcached中數(shù)據(jù)量的添加而添加。當(dāng)其它命令由于等待(遍歷全部item的命令運(yùn)行完成)而不能得到運(yùn)行。因而堵塞將發(fā)生。
5、 ?memcached能接受的key的最大長(zhǎng)度是250個(gè)字符memcached能接受的key的最大長(zhǎng)度是250個(gè)字符。
須要注意的是,250是memcachedserver端內(nèi)部的限制。假設(shè)使用的Memcachedclient支持"key的前綴"或類(lèi)似特性。那么key(前綴+原始key)的最大長(zhǎng)度是能夠超過(guò)250個(gè)字符的。推薦使用較短的key。這樣能夠節(jié)省內(nèi)存和帶寬。
6、 ?單個(gè)item的大小被限制在1M byte之內(nèi)由于內(nèi)存分配器的算法就是這種。
具體的回答:
1)Memcached的內(nèi)存存儲(chǔ)引擎,使用slabs來(lái)管理內(nèi)存。內(nèi)存被分成大小不等的slabs chunks(先分成大小相等的slabs,然后每一個(gè)slab被分成大小相等chunks,不同slab的chunk大小是不相等的)。chunk的大小依次從一個(gè)最小數(shù)開(kāi)始,按某個(gè)因子增長(zhǎng)。直到達(dá)到最大的可能值。假設(shè)最小值為400B,最大值是1MB,因子是1.20。各個(gè)slab的chunk的大小依次是:
slab1 - 400B;slab2 - 480B;slab3 - 576B ...slab中chunk越大。它和前面的slab之間的間隙就越大。因此。最大值越大。內(nèi)存利用率越低。Memcached必須為每一個(gè)slab預(yù)先分配內(nèi)存,因此假設(shè)設(shè)置了較小的因子和較大的最大值,會(huì)須要為Memcached提供很多其它的內(nèi)存。
2)不要嘗試向memcached中存取非常大的數(shù)據(jù),比如把巨大的網(wǎng)頁(yè)放到mencached中。由于將大數(shù)據(jù)load和unpack到內(nèi)存中須要花費(fèi)非常長(zhǎng)的時(shí)間,從而導(dǎo)致系統(tǒng)的性能反而不好。假設(shè)確實(shí)須要存儲(chǔ)大于1MB的數(shù)據(jù),能夠改動(dòng)slabs.c:POWER_BLOCK的值。然后又一次編譯memcached;或者使用低效的malloc/free。另外。能夠使用數(shù)據(jù)庫(kù)、MogileFS等方案取代Memcached系統(tǒng)。
7、 ?memcached的內(nèi)存分配器是怎樣工作的?為什么不適用malloc/free!
?為何要使用slabs?
實(shí)際上,這是一個(gè)編譯時(shí)選項(xiàng)。默認(rèn)會(huì)使用內(nèi)部的slab分配器,并且確實(shí)應(yīng)該使用內(nèi)建的slab分配器。最早的時(shí)候,memcached僅僅使用malloc/free來(lái)管理內(nèi)存。然而,這樣的方式不能與OS的內(nèi)存管理曾經(jīng)非常好地工作。重復(fù)地malloc/free造成了內(nèi)存碎片,OS終于花費(fèi)大量的時(shí)間去查找連續(xù)的內(nèi)存塊來(lái)滿(mǎn)足malloc的請(qǐng)求,而不是執(zhí)行memcached進(jìn)程。slab分配器就是為了解決問(wèn)題而生的。內(nèi)存被分配并劃分成chunks。一直被重復(fù)使用。由于內(nèi)存被劃分成大小不等的slabs。假設(shè)item的大小與被選擇存放它的slab不是非常合適的話(huà),就會(huì)浪費(fèi)一些內(nèi)存。
8、memcached對(duì)item的過(guò)期時(shí)間有什么限制?
item對(duì)象的過(guò)期時(shí)間最長(zhǎng)能夠達(dá)到30天。memcached把傳入的過(guò)期時(shí)間(時(shí)間段)解釋成時(shí)間點(diǎn)后。一旦到了這個(gè)時(shí)間點(diǎn),memcached就把item置為失效狀態(tài)。這是一個(gè)簡(jiǎn)單但obscure的機(jī)制。
9、什么是二進(jìn)制協(xié)議,是否須要關(guān)注?
二進(jìn)制協(xié)議嘗試為端提供一個(gè)更有效的、可靠的協(xié)議,降低client/server端因處理協(xié)議而產(chǎn)生的CPU時(shí)間。
依據(jù)Facebook的測(cè)試。解析ASCII協(xié)議是memcached中消耗CPU時(shí)間最多的
環(huán)節(jié)。
10、 memcached的內(nèi)存分配器是怎樣工作的?為什么不適用malloc/free。?為何要使用slabs?
實(shí)際上。這是一個(gè)編譯時(shí)選項(xiàng)。默認(rèn)會(huì)使用內(nèi)部的slab分配器,并且確實(shí)應(yīng)該使用內(nèi)建的slab分配器。
最早的時(shí)候,memcached僅僅使用malloc/free來(lái)管理內(nèi)存。然而,這樣的方式不能與OS的內(nèi)存管理曾經(jīng)非常好地工作。
重復(fù)地malloc/free造成了內(nèi)存碎片,OS終于花費(fèi)大量的時(shí)間去查找連續(xù)的內(nèi)存塊來(lái)滿(mǎn)足malloc的請(qǐng)求,而不是執(zhí)行memcached進(jìn)程。slab分配器就是為了解決問(wèn)題而生的。內(nèi)存被分配并劃分成chunks,一直被重復(fù)使用。由于內(nèi)存被劃分成大小不等的slabs。假設(shè)item的大小與被選擇存放它的slab不是非常合適的話(huà),就會(huì)浪費(fèi)一些內(nèi)存。
11、memcached是原子的嗎?
全部的被發(fā)送到memcached的單個(gè)命令是全然原子的。假設(shè)您針對(duì)同一份數(shù)據(jù)同一時(shí)候發(fā)送了一個(gè)set命令和一個(gè)get命令,它們不會(huì)影響對(duì)方。它們將被串行化、先后運(yùn)行。
即使在多線(xiàn)程模式。全部的命令都是原子的。然是,命令序列不是原子的。假設(shè)首先通過(guò)get命令獲取了一個(gè)item,改動(dòng)了它,然后再把它set回memcached,系統(tǒng)不保證這個(gè)item沒(méi)有被其它進(jìn)程(process,未必是操作系統(tǒng)中的進(jìn)程)操作過(guò)。memcached 1.2.5以及更高版本號(hào),提供了gets和cas命令,它們能夠解決上面的問(wèn)題。
假設(shè)使用gets命令查詢(xún)某個(gè)key的item,memcached會(huì)返回該item當(dāng)前值的唯一標(biāo)識(shí)。
假設(shè)client程序覆寫(xiě)了這個(gè)item并想把它寫(xiě)回到memcached中。能夠通過(guò)cas命令把那個(gè)唯一標(biāo)識(shí)一起發(fā)送給memcached。假設(shè)該item存放在memcached中的唯一標(biāo)識(shí)與您提供的一致,寫(xiě)操作將會(huì)成功。假設(shè)還有一個(gè)進(jìn)程在這期間也改動(dòng)了這個(gè)item,那么該item存放在memcached中的唯一標(biāo)識(shí)將會(huì)改變,寫(xiě)操作就會(huì)
失敗。
具體了解Memcached的內(nèi)存分配機(jī)制:
http://cjjwzs.javaeye.com/blog/762453
???
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(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ì)您有幫助就好】元
