天天看點

Memcache存儲大資料的問題

      Memcached存儲單個item最大資料是在1MB内,假設資料超過1M,存取set和get是都是傳回false,并且引起性能的問題。

我們之前對排行榜的資料進行緩存,因為排行榜在我們全部sql select查詢裡面占了30%,并且我們排行榜每小時更新一次,是以必須對資料做緩存。為了清除緩存友善,把全部的使用者的資料放在同一key中,因為memcached:set的時候沒有壓縮資料。在測試服測試的時候,沒發現問題,當上線的時候,結果發現,線上人數剛剛490人的時候,serverload average飄到7.9。然後我們去掉緩存,一下子就下降到0.59。

是以Memcahce不适合緩存大資料,超過1MB的資料,能夠考慮在client壓縮或拆分到多個key中。大的資料在進行load和uppack到記憶體的時候須要花非常長時間,進而減少server的性能。

Memcached支援最大的存儲對象為1M。這個值由其記憶體配置設定機制決定的。

memcached預設情況下採用了名為Slab Allocator的機制配置設定、管理記憶體。在該機制出現曾經,記憶體的配置設定是通過對全部記錄簡單地進行malloc和free來進行的。可是,這樣的方式會導緻記憶體碎片,加重作業系統記憶體管理器的負擔,最壞的情況下,會導緻作業系統比memcached程序本身還慢。Slab

Allocator就是為解決該問題而誕生的。Slab Allocator的基本原理是依照預先規定的大小,将配置設定的記憶體切割成特定長度的塊,以全然解決記憶體碎片問題.

今天(2012-03-16)我們又一次測試了memcached ::set的資料大小。可能是我們用php的memcached擴充是最新版,set資料的時候是預設壓縮的。set 資料:

$ac = new memcahed();
$data = str_repeat('a', 1024* 1024); //1M的資料
$r  =  $ac->set('key', $data, 9999);
//或者
$data = str_repeat('a', 1024* 1024*100);//100M的資料
$r  =  $ac->set('key', $data, 9999);      

不論是1M的資料還是100M的資料,都能set成功。後來我發現,memcachedset資料的時候是預設壓縮的。因為這個這個是反複的字元串,壓縮率高達1000倍。是以100M的資料壓縮後實際也就100k而已。

當我設定:

$ac->setOption(memcahed::OPT_COMPRESSION,0); //不壓縮存儲資料。
$data = str_repeat('a', 1024* 1024); //1M資料
$r  =  $ac->set('key', $data, 9999);//1M的資料set不成功。      

也就是說memcached server不能存儲超過1M的資料,可是經過client壓縮資料後,僅僅要小于1M的資料都能存儲成功。

memcached相關知識:

1、memcached的基本設定

1)啟動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選項是啟動一個守護程序,

-m是配置設定給Memcache使用的記憶體數量,機關是MB,我這裡是10MB,

-u是執行Memcache的使用者,我這裡是root,

-l是監聽的serverIP位址,假設有多個位址的話,我這裡指定了server的IP位址192.168.0.200,

-p是設定Memcache監聽的port,我這裡設定了12000,最好是1024以上的port,

-c選項是最大執行的并發連接配接數,預設是1024,我這裡設定了256,依照你server的負載量來設定,

-P是設定儲存Memcache的pid檔案,我這裡是儲存在 /tmp/memcached.pid,

2)假設要結束Memcache程序,運作:

# kill `cat /tmp/memcached.pid`

雜湊演算法将随意長度的二進制值映射為固定長度的較小二進制值,這個小的二進制值稱為哈希值。哈希值是一段資料唯一且極其緊湊的數值表示形式。假設散列一段明文并且哪怕僅僅更改該

段落的一個字母,随後的哈希都将産生不同的值。要找到散列為同一個值的兩個不同的輸入,在計算上是不可能的。

2、适用memcached的業務場景?

1)假設站點包括了訪問量非常大的動态網頁,因而資料庫的負載将會非常高。因為大部分資料庫請求都是讀操作,那麼memcached能夠顯著地減小資料庫負載。

2)假設資料庫server的負載比較低但CPU使用率非常高,這時能夠緩存計算好的結果( computed objects )和渲染後的網頁模闆(enderred templates)。

3)利用memcached能夠緩存session資料、暫時資料以降低對他們的資料庫寫操作。

4)緩存一些非常小可是被頻繁訪問的檔案。

5)緩存Web 'services'(非IBM宣揚的Web Services,譯者注)或RSS feeds的結果.。

3、不适用memcached的業務場景?

1)緩存對象的大小大于1MB

Memcached本身就不是為了處理龐大的多媒體(large media)和巨大的二進制塊(streaming huge blobs)而設計的。

2)key的長度大于250字元

3)虛拟主機不讓執行memcached服務

     假設應用本身托管在低端的虛拟私有server上,像vmware, xen這類虛拟化技術并不适合執行memcached。Memcached須要接管和控制大塊的記憶體,假設memcached管理      的記憶體被OS或 hypervisor交換出去,memcached的性能将大打折扣。

4)應用執行在不安全的環境中

Memcached為提供不論什麼安全政策,隻通過telnet就能夠訪問到memcached。假設應用執行在共享的系統上,須要着重考慮安全問題。

5)業務本身須要的是持久化資料或者說須要的應該是database

4、 不能可以周遊memcached中全部的item

     這個操作的速度相對緩慢且堵塞其它的操作(這裡的緩慢時相比memcached其它的指令)。memcached全部非調試(non-debug)指令,比如add, set, get, fulsh等不管

memcached中存儲了多少資料,它們的運作都僅僅消耗常量時間。不論什麼周遊全部item的指令運作所消耗的時間,将随着memcached中資料量的添加而添加。當其它指令由于等待(周遊全部item的指令運作完成)而不能得到運作,因而堵塞将發生。

5、  memcached能接受的key的最大長度是250個字元

memcached能接受的key的最大長度是250個字元。須要注意的是,250是memcachedserver端内部的限制。假設使用的Memcachedclient支援"key的字首"或類似特性,那麼key(字首+原始key)的最大長度是能夠超過250個字元的。推薦使用較短的key,這樣能夠節省記憶體和帶寬。

6、  單個item的大小被限制在1M byte之内

由于記憶體配置設定器的算法就是這種。

具體的回答:

1)Memcached的記憶體存儲引擎,使用slabs來管理記憶體。記憶體被分成大小不等的slabs chunks(先分成大小相等的slabs,然後每一個slab被分成大小相等chunks,不同slab的chunk大小是不相等的)。chunk的大小依次從一個最小數開始,按某個因子增長,直到達到最大的可能值。假設最小值為400B,最大值是1MB,因子是1.20,各個slab的chunk的大小依次是:

slab1 - 400B;slab2 - 480B;slab3 - 576B ...slab中chunk越大,它和前面的slab之間的間隙就越大。是以,最大值越大,記憶體使用率越低。Memcached必須為每一個slab預先配置設定記憶體,是以假設設定了較小的因子和較大的最大值,會須要為Memcached提供很多其它的記憶體。

2)不要嘗試向memcached中存取非常大的資料,比如把巨大的網頁放到mencached中。由于将大資料load和unpack到記憶體中須要花費非常長的時間,進而導緻系統的性能反而不好。假設确實須要存儲大于1MB的資料,能夠改動slabs.c:POWER_BLOCK的值,然後又一次編譯memcached;或者使用低效的malloc/free。另外,能夠使用資料庫、MogileFS等方案取代Memcached系統。

7、  memcached的記憶體配置設定器是怎樣工作的?為什麼不适用malloc/free!?為何要使用slabs?

實際上,這是一個編譯時選項。預設會使用内部的slab配置設定器,并且确實應該使用内建的slab配置設定器。最早的時候,memcached僅僅使用malloc/free來管理記憶體。然而,這樣的方式不能與OS的記憶體管理曾經非常好地工作。重複地malloc/free造成了記憶體碎片,OS終于花費大量的時間去查找連續的記憶體塊來滿足malloc的請求,而不是執行memcached程序。slab配置設定器就是為了解決問題而生的。記憶體被配置設定并劃分成chunks,一直被重複使用。由于記憶體被劃分成大小不等的slabs,假設item的大小與被選擇存放它的slab不是非常合适的話,就會浪費一些記憶體。

8、memcached對item的過期時間有什麼限制?

item對象的過期時間最長能夠達到30天。memcached把傳入的過期時間(時間段)解釋成時間點後,一旦到了這個時間點,memcached就把item置為失效狀态,這是一個簡單但obscure的機制。

9、什麼是二進制協定,是否須要關注?

二進制協定嘗試為端提供一個更有效的、可靠的協定,降低client/server端因處理協定而産生的CPU時間。依據Facebook的測試,解析ASCII協定是memcached中消耗CPU時間最多的

環節。

10、 memcached的記憶體配置設定器是怎樣工作的?為什麼不适用malloc/free!?為何要使用slabs?

11、memcached是原子的嗎?

全部的被發送到memcached的單個指令是全然原子的。假設您針對同一份資料同一時候發送了一個set指令和一個get指令,它們不會影響對方。它們将被串行化、先後運作。即使在多線程模式,全部的指令都是原子的。然是,指令序列不是原子的。假設首先通過get指令擷取了一個item,改動了它,然後再把它set回memcached,系統不保證這個item沒有被其它程序(process,未必是作業系統中的程序)操作過。memcached 1.2.5以及更高版本号,提供了gets和cas指令,它們能夠解決上面的問題。假設使用gets指令查詢某個key的item,memcached會傳回該item目前值的唯一辨別。假設client程式覆寫了這個item并想把它寫回到memcached中,能夠通過cas指令把那個唯一辨別一起發送給memcached。假設該item存放在memcached中的唯一辨別與您提供的一緻,寫操作将會成功。假設還有一個程序在這期間也改動了這個item,那麼該item存放在memcached中的唯一辨別将會改變,寫操作就會

失敗。