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