基本問(wè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ù)載量來(lái)設(shè)定,
-P是設(shè)置保存Memcache的pid文件,我這里是保存在 /tmp/memcached.pid,

2)如果要結(jié)束Memcache進(jìn)程,執(zhí)行:

# kill `cat /tmp/memcached.pid`

哈希算法任意長(zhǎng)度的二進(jìn)制值映射為固定長(zhǎng)度的較小二進(jìn)制值,這個(gè)小的二進(jìn)制值稱為哈希值。哈希值是一段數(shù)據(jù)唯一且極其緊湊的數(shù)值表示形式。如果散列一段明文而且哪怕只更改該

段落的一個(gè)字母,隨后的哈希都將產(chǎn)生不同的值。要找到散列為同一個(gè)值的兩個(gè)不同的輸入,在計(jì)算上是不可能的。

2、一致性Hash算法的目的有兩點(diǎn):一是節(jié)點(diǎn)變動(dòng)后其他節(jié)點(diǎn)受影響盡可能小;二是節(jié)點(diǎn)變動(dòng)后數(shù)據(jù)重新分配盡可能均衡 。

3、為什么要運(yùn)行 memcached ?

如果網(wǎng)站的高流量很大并且大多數(shù)的訪問(wèn)會(huì)造成數(shù)據(jù)庫(kù)高負(fù)荷的狀況下,使用 memcached 能夠減輕數(shù)據(jù)庫(kù)的壓力。

4、適用memcached的業(yè)務(wù)場(chǎng)景?

1)如果網(wǎng)站包含了訪問(wèn)量很大的動(dòng)態(tài)網(wǎng)頁(yè),因而數(shù)據(jù)庫(kù)的負(fù)載將會(huì)很高。由于大部分?jǐn)?shù)據(jù)庫(kù)請(qǐng)求都是讀操作,那么memcached可以顯著地減小數(shù)據(jù)庫(kù)負(fù)載。

2)如果數(shù)據(jù)庫(kù)服務(wù)器的負(fù)載比較低但CPU使用率很高,這時(shí)可以緩存計(jì)算好的結(jié)果( computed objects )和渲染后的網(wǎng)頁(yè)模板(enderred templates)。

3)利用memcached可以緩存session數(shù)據(jù)、臨時(shí)數(shù)據(jù)以減少對(duì)他們的數(shù)據(jù)庫(kù)寫操作。

4)緩存一些很小但是被頻繁訪問(wèn)的文件。

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

5、不適用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ī)不讓運(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為提供任何安全策略,僅僅通過(guò)telnet就可以訪問(wèn)到memcached。如果應(yīng)用運(yùn)行在共享的系統(tǒng)上,需要著重考慮安全問(wèn)題。

5)業(yè)務(wù)本身需要的是持久化數(shù)據(jù)或者說(shuō)需要的應(yīng)該是database

6、能夠遍歷memcached中所有的item嗎?

不能,這個(gè)操作的速度相對(duì)緩慢且阻塞其他的操作(這里的緩慢時(shí)相比memcached其他的命令)。memcached所有非調(diào)試(non-debug)命令,例如add, set, get, fulsh等無(wú)論

memcached中存儲(chǔ)了多少數(shù)據(jù),它們的執(zhí)行都只消耗常量時(shí)間。任何遍歷所有item的命令執(zhí)行所消耗的時(shí)間,將隨著memcached中數(shù)據(jù)量的增加而增加。當(dāng)其他命令因?yàn)榈却ū闅v所

有item的命令執(zhí)行完畢)而不能得到執(zhí)行,因而阻塞將發(fā)生。

集群的相關(guān)問(wèn)題

7、memcached是怎么工作的?

Memcached的高性能源于兩階段哈希(two-stage hash)結(jié)構(gòu)。Memcached就像一個(gè)巨大的、存儲(chǔ)了很多<key,value>對(duì)的哈希表。通過(guò)key,可以存儲(chǔ)或查詢?nèi)我獾臄?shù)據(jù)。 客戶端

可以把數(shù)據(jù)存儲(chǔ)在多臺(tái)memcached上。當(dāng)查詢數(shù)據(jù)時(shí),客戶端首先參考節(jié)點(diǎn)列表計(jì)算出key的哈希值(階段一哈希),進(jìn)而選中一個(gè)節(jié)點(diǎn);客戶端將請(qǐng)求發(fā)送給選中的節(jié)點(diǎn),然后

memcached節(jié)點(diǎn)通過(guò)一個(gè)內(nèi)部的哈希算法(階段二哈希),查找真正的數(shù)據(jù)(item)并返回給客戶端。從實(shí)現(xiàn)的角度看,memcached是一個(gè)非阻塞的、基于事件的服務(wù)器程序。

8、memcached最大的優(yōu)勢(shì)是什么?

Memcached最大的好處就是它帶來(lái)了極佳的水平可擴(kuò)展性,特別是在一個(gè)巨大的系統(tǒng)中。由于客戶端自己做了一次哈希,那么我們很容易增加大量memcached到集群中。memcached

之間沒(méi)有相互通信,因此不會(huì)增加 memcached的負(fù)載;沒(méi)有多播協(xié)議,不會(huì)網(wǎng)絡(luò)通信量爆炸(implode)。

9、memcached和MySQL的query cache相比,有什么優(yōu)缺點(diǎn)?

缺點(diǎn):

1)相比MySQL的query cache,把memcached引入應(yīng)用中需要不少的工作量。MySQL的query cache,可以自動(dòng)地緩存SQL查詢的結(jié)果,被緩存的SQL查詢可以被反復(fù)、快速的執(zhí)行。

優(yōu)點(diǎn):

1)當(dāng)修改表時(shí),MySQL的query cache會(huì)立刻被刷新(flush)。當(dāng)寫操作很頻繁時(shí),MySQL的query cache會(huì)經(jīng)常讓所有緩存數(shù)據(jù)都失效。

2)在多核CPU上,MySQL的query cache會(huì)遇到擴(kuò)展問(wèn)題(scalability issues)。在多核CPU上,query cache會(huì)增加一個(gè)全局鎖(global lock), 由于需要刷新更多的緩存數(shù)據(jù),速度

會(huì)變得更慢。

3)在MySQL的query cache中,是不能存儲(chǔ)任意的數(shù)據(jù)的(只能是SQL查詢結(jié)果)。利用memcached,我們可以搭建出各種高效的緩存。比如,可以執(zhí)行多個(gè)獨(dú)立的查詢,構(gòu)建出一個(gè)

用戶對(duì)象(user object),然后將用戶對(duì)象緩存到memcached中。而query cache是SQL語(yǔ)句級(jí)別的,不可能做到這一點(diǎn)。在小的網(wǎng)站中,query cache會(huì)有所幫助,但隨著網(wǎng)站規(guī)模的

增加,query cache的弊將大于利。

4)query cache能夠利用的內(nèi)存容量受到MySQL服務(wù)器空閑內(nèi)存空間的限制。給數(shù)據(jù)庫(kù)服務(wù)器增加更多的內(nèi)存來(lái)緩存數(shù)據(jù),固然是很好的。但是,有了memcached,只要您有空閑的內(nèi)

存,都可以用來(lái)增加memcached集群的規(guī)模,然后您就可以緩存更多的數(shù)據(jù)。

10、memcached和服務(wù)器的local cache(比如PHP的APC、mmap文件等)相比,有什么優(yōu)缺點(diǎn)?

1)首先,local cache面臨著嚴(yán)重的內(nèi)存限制,能夠利用的內(nèi)存容量受到(單臺(tái))服務(wù)器空閑內(nèi)存空間的限制。

2)local cache有一點(diǎn)比memcached和query cache都要好,那就是它不但可以存儲(chǔ)任意的數(shù)據(jù),而且沒(méi)有網(wǎng)絡(luò)存取的延遲。因此,local cache的數(shù)據(jù)查詢更快。考慮把highly

common的數(shù)據(jù)放在local cache中吧。如果每個(gè)頁(yè)面都需要加載一些數(shù)量較少的數(shù)據(jù),可以考慮把它們放在local cached。

3)local cache缺少集體失效(group invalidation)的特性。在memcached集群中,刪除或更新一個(gè)key會(huì)讓所有的觀察者覺察到。但是在local cache中, 我們只能通知所有的服務(wù)器

刷新cache(很慢,不具擴(kuò)展性)或者僅僅依賴緩存超時(shí)失效機(jī)制。

11、memcached的cache機(jī)制是怎樣的?

Memcached主要的cache機(jī)制是LRU(最近最少用)算法+超時(shí)失效。當(dāng)您存數(shù)據(jù)到memcached中,可以指定該數(shù)據(jù)在緩存中可以呆多久Which is forever, or some time in the

future。如果memcached的內(nèi)存不夠用了,過(guò)期的slabs會(huì)優(yōu)先被替換,接著就輪到最老的未被使用的slabs。

12、memcached如何實(shí)現(xiàn)冗余機(jī)制?

不實(shí)現(xiàn)!Memcached應(yīng)該是應(yīng)用的緩存層,從設(shè)計(jì)本身來(lái)京就不帶有任何冗余機(jī)制。如果一個(gè)memcached節(jié)點(diǎn)失去了所有數(shù)據(jù),應(yīng)該可以從數(shù)據(jù)源(比如數(shù)據(jù)庫(kù))再次獲取到數(shù)據(jù)。應(yīng)

用系統(tǒng)應(yīng)該可以容忍節(jié)點(diǎn)的失效。如果擔(dān)心節(jié)點(diǎn)失效會(huì)大大加重?cái)?shù)據(jù)庫(kù)的負(fù)擔(dān),那么可以采取一些辦法。比如您可以增加更多的節(jié)點(diǎn)(來(lái)減少丟失一個(gè)節(jié)點(diǎn)的影響),熱備節(jié)點(diǎn)(在其他節(jié)

點(diǎn)down了的時(shí)候接管IP)等等。

13、memcached如何處理容錯(cuò)的?

在節(jié)點(diǎn)失效的情況下,集群沒(méi)有必要做任何容錯(cuò)處理。如果發(fā)生了節(jié)點(diǎn)失效,應(yīng)對(duì)的措施完全取決于用戶。

節(jié)點(diǎn)失效時(shí),下面列出幾種方案供您選擇:

1)忽略它! 在失效節(jié)點(diǎn)被恢復(fù)或替換之前,還有很多其他節(jié)點(diǎn)可以應(yīng)對(duì)節(jié)點(diǎn)失效帶來(lái)的影響。

2)把失效的節(jié)點(diǎn)從節(jié)點(diǎn)列表中移除。做這個(gè)操作千萬(wàn)要小心!在默認(rèn)情況下(余數(shù)式哈希算法),客戶端添加或移除節(jié)點(diǎn),會(huì)導(dǎo)致所有的緩存數(shù)據(jù)不可用!因?yàn)楣⒄盏墓?jié)點(diǎn)列表變化

了,大部分key會(huì)因?yàn)楣V档母淖兌挥成涞剑ㄅc原來(lái))不同的節(jié)點(diǎn)上。

3)啟動(dòng)熱備節(jié)點(diǎn),接管失效節(jié)點(diǎn)所占用的IP。這樣可以防止哈希紊亂(hashing chaos)。

4)如果希望添加和移除節(jié)點(diǎn),而不影響原先的哈希結(jié)果,可以使用一致性哈希算法(consistent hashing)。

5)兩次哈希(reshing)。當(dāng)客戶端存取數(shù)據(jù)時(shí),如果發(fā)現(xiàn)一個(gè)節(jié)點(diǎn)down了,就再做一次哈希(哈希算法與前一次不同),重新選擇另一個(gè)節(jié)點(diǎn)(需要注意的時(shí),客戶端并沒(méi)有把down

的節(jié)點(diǎn)從節(jié)點(diǎn)列表中移除,下次還是有可能先哈希到它)。如果某個(gè)節(jié)點(diǎn)時(shí)好時(shí)壞,兩次哈希的方法就有風(fēng)險(xiǎn)了,好的節(jié)點(diǎn)和壞的節(jié)點(diǎn)上都可能存在臟數(shù)據(jù)(stale data)。

14、如何將memcached中item批量導(dǎo)入導(dǎo)出?

不應(yīng)該這樣做!Memcached是一個(gè)非阻塞的服務(wù)器。任何可能導(dǎo)致memcached暫停或瞬時(shí)拒絕服務(wù)的操作都應(yīng)該值得深思熟慮。向memcached中批量導(dǎo)入數(shù)據(jù)往往不是您真正想要

的!想象看,如果緩存數(shù)據(jù)在導(dǎo)出導(dǎo)入之間發(fā)生了變化,您就需要處理臟數(shù)據(jù)了;如果緩存數(shù)據(jù)在導(dǎo)出導(dǎo)入之間過(guò)期了,您又怎么處理這些數(shù)據(jù)呢?

因此,批量導(dǎo)出導(dǎo)入數(shù)據(jù)并不像想象中的那么有用。不過(guò)在一個(gè)場(chǎng)景倒是很有用。如果您有大量的從不變化 的數(shù)據(jù),并且希望緩存很快熱(warm)起來(lái),批量導(dǎo)入緩存數(shù)據(jù)是很有幫助

的。

15、但是我確實(shí)需要把memcached中的item批量導(dǎo)出導(dǎo)入,怎么辦??

如果需要批量導(dǎo)出和導(dǎo)入,最可能的原因一般是重新生成緩存數(shù)據(jù)需要消耗很長(zhǎng)的時(shí)間或者數(shù)據(jù)庫(kù)壞了讓您飽受痛苦。

如果一個(gè)memcached節(jié)點(diǎn)down了讓您很痛苦,那么必須對(duì)數(shù)據(jù)庫(kù)做一些優(yōu)化工作。比如處理"驚群"問(wèn)題( memcached節(jié)點(diǎn)都失效了,反復(fù)的查詢讓數(shù)據(jù)庫(kù)不堪重負(fù))或者存在優(yōu)化不

好的查詢等。Memcached 并不是逃避優(yōu)化查詢的借口和方案。

這里給出一些提示:

使用MogileFS(或者CouchDB等類似的軟件)在存儲(chǔ)item,把item計(jì)算出來(lái)并dump到磁盤上。MogileFS可以很方便地覆寫item,并提供快速地訪問(wèn)。甚至可以把MogileFS中的item

緩存在memcached中,這樣可以加快讀取速度。 MogileFS+Memcached的組合可以加快緩存不命中時(shí)的響應(yīng)速度,提高網(wǎng)站的可用性。

重新使用MySQL。MySQL的 InnoDB主鍵查詢速度非常快。如果大部分緩存數(shù)據(jù)都可以放到VARCHAR字段中,那么主鍵查詢的性能將更好。從memcached中按key查詢幾乎等價(jià)于

MySQL的主鍵查詢:將key 哈希到64-bit的整數(shù),然后將數(shù)據(jù)存儲(chǔ)到MySQL中。您可以把原始(不做哈希)的key存儲(chǔ)都普通的字段中,然后建立二級(jí)索引來(lái)加快查詢...key被動(dòng)地失效,

批量刪除失效的key,等等。

16、memcached是如何做身份驗(yàn)證的?

沒(méi)有身份認(rèn)證機(jī)制!memcached是運(yùn)行在應(yīng)用下層的軟件(身份驗(yàn)證應(yīng)該是應(yīng)用上層的職責(zé))。memcached的客戶端和服務(wù)器端之所以是輕量級(jí)的,部分原因就是完全沒(méi)有實(shí)現(xiàn)身份驗(yàn)

證機(jī)制。這樣,memcached可以很快地創(chuàng)建新連接,服務(wù)器端也無(wú)需任何配置。如果您希望限制訪問(wèn),您可以使用防火墻,或者讓memcached監(jiān)聽unix domain socket。

17、memcached的多線程是什么?如何使用它們?

線程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本擁有了多線程模式。多線程模式允許memcached能夠充分利用多個(gè)CPU,并在

CPU之間共享所有的緩存數(shù)據(jù)。memcached使用一種簡(jiǎn)單的鎖機(jī)制來(lái)保證數(shù)據(jù)更新操作的互斥。相比在同一個(gè)物理機(jī)器上運(yùn)行多個(gè)memcached實(shí)例,這種方式能夠更有效地處理multi

gets。如果系統(tǒng)的負(fù)載并不重,那么不需要啟用多線程工作模式。如果您在運(yùn)行一個(gè)擁有大規(guī)模硬件的、龐大的網(wǎng)站,將體驗(yàn)到看到多線程的好處。更多信息請(qǐng)參見:

http://code.sixapart.com/svn/memcached/trunk/server/doc/threads.txt

簡(jiǎn)單地總結(jié)一下:命令解析(memcached在這里花了大部分時(shí)間)可以運(yùn)行在多線程模式下。memcached內(nèi)部對(duì)數(shù)據(jù)的操作是基于很多全局鎖的(因此這部分工作不是多線程的)。未

來(lái)對(duì)多線程模式的改進(jìn),將移除大量的全局鎖,提高memcached在負(fù)載極高的場(chǎng)景下的性能。

18、memcached能接受的key的最大長(zhǎng)度是多少?

memcached能接受的key的最大長(zhǎng)度是250個(gè)字符。需要注意的是,250是memcached服務(wù)器端內(nèi)部的限制。如果使用的Memcached客戶端支持"key的前綴"或類似特性,那么key

(前綴+原始key)的最大長(zhǎng)度是可以超過(guò)250個(gè)字符的。推薦使用較短的key,這樣可以節(jié)省內(nèi)存和帶寬。

19、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ī)制。

20、memcached最大能存儲(chǔ)多大的單個(gè)item?

memcached最大能存儲(chǔ)1MB的單個(gè)item。如果需要被緩存的數(shù)據(jù)大于1MB,可以考慮在客戶端壓縮或拆分到多個(gè)key中。

21、為什么單個(gè)item的大小被限制在1M byte之內(nèi)?

簡(jiǎn)單的回答:因?yàn)閮?nèi)存分配器的算法就是這樣的。

詳細(xì)的回答:

1)Memcached的內(nèi)存存儲(chǔ)引擎,使用slabs來(lái)管理內(nèi)存。內(nèi)存被分成大小不等的slabs chunks(先分成大小相等的slabs,然后每個(gè)slab被分成大小相等chunks,不同slab的chunk大小

是不相等的)。chunk的大小依次從一個(gè)最小數(shù)開始,按某個(gè)因子增長(zhǎng),直到達(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è)置了較小的因子和較大的最大值,會(huì)需要為Memcached提供更多的內(nèi)存。

2)不要嘗試向memcached中存取很大的數(shù)據(jù),例如把巨大的網(wǎng)頁(yè)放到mencached中。因?yàn)閷⒋髷?shù)據(jù)load和unpack到內(nèi)存中需要花費(fèi)很長(zhǎng)的時(shí)間,從而導(dǎo)致系統(tǒng)的性能反而不好。如果

確實(shí)需要存儲(chǔ)大于1MB的數(shù)據(jù),可以修改slabs.c:POWER_BLOCK的值,然后重新編譯memcached;或者使用低效的malloc/free。另外,可以使用數(shù)據(jù)庫(kù)、MogileFS等方案代替

Memcached系統(tǒng)。

22、可以在不同的memcached節(jié)點(diǎn)上使用大小不等的緩存空間嗎?如果這么做之后,memcached能夠更有效地使用內(nèi)存嗎?

Memcache客戶端僅根據(jù)哈希算法來(lái)決定將某個(gè)key存儲(chǔ)在哪個(gè)節(jié)點(diǎn)上,而不考慮節(jié)點(diǎn)的內(nèi)存大小。因此,可以在不同的節(jié)點(diǎn)上使用大小不等的內(nèi)存作為緩存空間。但是一般可以這樣做

:擁有較多內(nèi)存的節(jié)點(diǎn)上可以運(yùn)行多個(gè)memcached實(shí)例,每個(gè)實(shí)例使用的內(nèi)存跟其他節(jié)點(diǎn)上的實(shí)例相同。

23、什么是二進(jìn)制協(xié)議,是否需要關(guān)注?

二進(jìn)制協(xié)議嘗試為端提供一個(gè)更有效的、可靠的協(xié)議,減少客戶端/服務(wù)器端因處理協(xié)議而產(chǎn)生的CPU時(shí)間。根據(jù)Facebook的測(cè)試,解析ASCII協(xié)議是memcached中消耗CPU時(shí)間最多的

環(huán)節(jié)。

24、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)存管理以前很好地工作。反復(fù)地malloc/free造成了內(nèi)存碎片,OS最終花費(fèi)大量的時(shí)間去查找連續(xù)的內(nèi)存塊來(lái)滿足malloc的請(qǐng)求,而不是運(yùn)行memcached進(jìn)程。slab分配器就是

為了解決這個(gè)問(wèn)題而生的。內(nèi)存被分配并劃分成chunks,一直被重復(fù)使用。因?yàn)閮?nèi)存被劃分成大小不等的slabs,如果item的大小與被選擇存放它的slab不是很合適的話,就會(huì)浪費(fèi)一些內(nèi)存。

25、memcached是原子的嗎?

所有的被發(fā)送到memcached的單個(gè)命令是完全原子的。如果您針對(duì)同一份數(shù)據(jù)同時(shí)發(fā)送了一個(gè)set命令和一個(gè)get命令,它們不會(huì)影響對(duì)方。它們將被串行化、先后執(zhí)行。即使在多線程模

式,所有的命令都是原子的。然是,命令序列不是原子的。如果首先通過(guò)get命令獲取了一個(gè)item,修改了它,然后再把它set回memcached,系統(tǒng)不保證這個(gè)item沒(méi)有被其他進(jìn)程

(process,未必是操作系統(tǒng)中的進(jìn)程)操作過(guò)。memcached 1.2.5以及更高版本,提供了gets和cas命令,它們可以解決上面的問(wèn)題。如果使用gets命令查詢某個(gè)key的item,

memcached會(huì)返回該item當(dāng)前值的唯一標(biāo)識(shí)。如果客戶端程序覆寫了這個(gè)item并想把它寫回到memcached中,可以通過(guò)cas命令把那個(gè)唯一標(biāo)識(shí)一起發(fā)送給memcached。如果該item

存放在memcached中的唯一標(biāo)識(shí)與您提供的一致,寫操作將會(huì)成功。如果另一個(gè)進(jìn)程在這期間也修改了這個(gè)item,那么該item存放在memcached中的唯一標(biāo)識(shí)將會(huì)改變,寫操作就會(huì)

失敗。

性能和客戶端庫(kù)方面的問(wèn)題

26、memcached沒(méi)有我的database快,為什么?

在一對(duì)一比較中,memcached可能沒(méi)有SQL查詢快。但是,這不是memcached的設(shè)計(jì)目標(biāo)。Memcached的目標(biāo)是可伸縮性。當(dāng)連接和請(qǐng)求增加的時(shí)候,memcached的性能將比

大多數(shù)數(shù)據(jù)庫(kù)查詢好。可以先在高負(fù)載的環(huán)境(并發(fā)的連接和請(qǐng)求)中測(cè)試您的代碼,然后再?zèng)Q定memcached是否適合您。

27、使用不同的客戶端庫(kù),可以訪問(wèn)到memcached中相同的數(shù)據(jù)嗎?

從技術(shù)上說(shuō),是可以的。但是可能會(huì)遇到下面三個(gè)問(wèn)題:

1)不同的庫(kù)采用不同的方式序列化數(shù)據(jù)。舉個(gè)例子,perl的Cache::Memcached使用Storable來(lái)序列化結(jié)構(gòu)復(fù)雜的數(shù)據(jù)(比如hash references, objects, 等)。其他語(yǔ)言的客戶端庫(kù)很

可能不能讀取這種格式的數(shù)據(jù)。如果您要存儲(chǔ)復(fù)雜的數(shù)據(jù)并且想被多種客戶端庫(kù)讀取,那么您應(yīng)該以簡(jiǎn)單的string格式來(lái)存儲(chǔ),并且這種格式可以被JSON、XML等外部庫(kù)解析。

2)從某個(gè)客戶端來(lái)的數(shù)據(jù)被壓縮了,從另一個(gè)客戶端來(lái)的卻沒(méi)被壓縮。

3)各個(gè)客戶端庫(kù)可能使用不同的哈希算法(階段一哈希)。在連接到多個(gè)memcached服務(wù)器端的情況下,客戶端庫(kù)根據(jù)自身實(shí)現(xiàn)的哈希算法把key映射到某臺(tái)memcached上。正是因?yàn)?/p>

不同的客戶端庫(kù)使用不同的哈希算法,所以被Perl客戶端庫(kù)映射到memcached A的key,可能又會(huì)被Python客戶端庫(kù)映射到memcached B,等等。Perl客戶端庫(kù)還允許為每臺(tái)

memcached指定不同的權(quán)重(weight),這也是導(dǎo)致這個(gè)問(wèn)題的一個(gè)因素。

28、什么是一致性哈希的客戶端?

這里有一篇文章很好地解釋了它的用處:http://www.last.fm/user/RJ/journal/2007/04/10/392555

客戶端可以通過(guò)"前綴"來(lái)給key設(shè)置一個(gè)域(命名空間)。例如,在一個(gè)共享主機(jī)的環(huán)境中,可以將客戶姓名作為"前綴",為key創(chuàng)建一個(gè)特定的域。在存儲(chǔ)數(shù)據(jù)的時(shí)候,"前綴"可以用在

key上,但是不應(yīng)該參與哈希計(jì)算。目前,memcached自己還沒(méi)有實(shí)現(xiàn)針對(duì)復(fù)雜結(jié)構(gòu)數(shù)據(jù)的序列化方法,JSON則是一種被廣泛使用的對(duì)象序列化格式。

哈希 / 鍵分布

29、什么時(shí)候失效的數(shù)據(jù)項(xiàng)會(huì)從緩存中刪除?

memcached 使用懶失效,當(dāng)客戶端請(qǐng)求數(shù)據(jù)項(xiàng)時(shí), memcached 在返回?cái)?shù)據(jù)前會(huì)檢查失效時(shí)間來(lái)確定數(shù)據(jù)項(xiàng)是否已經(jīng)失效。同樣地,當(dāng)添加一個(gè)新的數(shù)據(jù)項(xiàng)時(shí),如果緩存已經(jīng)滿了, memcached 就會(huì)先替換失效的數(shù)據(jù)項(xiàng),然后才是緩存中最少使用的數(shù)據(jù)項(xiàng)。

命名空間

30、memcached 不支持命名空間。以下提供幾種模仿命名空間的方式:

1)用鍵的前綴模仿命名空間:在真實(shí)的鍵之前加入有意義的前綴。

2)用命名空間刪除數(shù)據(jù)項(xiàng):盡管 memcached 不支持使用任何類型的通配符或命名空間來(lái)完成刪除操作,但是可以采用一些技巧來(lái)替代:

在 PHP 中使用一個(gè)叫 foo 的命名空間:$ns_key = $memcache->get("foo_namespace_key");

// if not set, initialize it

if($ns_key=false) $memcache->set("foo_namespace_key", rand(1, 10000));

$my_key = "foo_".$ns_key."_12345";

清除命名空間:$memcache->increment("foo_namespace_key");

應(yīng)用設(shè)計(jì)

31、在設(shè)計(jì)應(yīng)用時(shí),可以通過(guò)Memcached緩存那些內(nèi)容?

1)緩存簡(jiǎn)單的查詢結(jié)果:查詢緩存存儲(chǔ)了給定查詢語(yǔ)句對(duì)應(yīng)的整個(gè)結(jié)果集,最合適緩存那些經(jīng)常被用到,但不會(huì)改變的 SQL 語(yǔ)句對(duì)查詢到的結(jié)果集,比如載入特定的過(guò)濾內(nèi)容。

$key = md5('SELECT * FROM rest_of_sql_statement_goes_here');

if ($memcache->get($key)) {

      ` return $memcache->get($key);`

}else {

    ` // Run the query and transform the result data into your final dataset form`

    ` $result = $query_results_mangled_into_most_likely_an_array`

     ` $memcache->set($key, $result, TRUE, 86400); // Store the result of the query for a day`

    ` return $result;`

}

記住,如果查詢語(yǔ)句對(duì)應(yīng)的結(jié)果集改變,該結(jié)果集不會(huì)展現(xiàn)出來(lái)。這種方法不總是有用,但它確實(shí)讓工作變得比較快。

2)緩存簡(jiǎn)單的基于行的查詢結(jié)果:基于行的緩存會(huì)檢查緩存數(shù)據(jù)key的列表,那些在緩存中的行可以直接被取出,不在緩存中的行將會(huì)從數(shù)據(jù)庫(kù)中取出并以唯一的鍵為標(biāo)識(shí)緩存起來(lái),最

后加入到最終的數(shù)據(jù)集中返回。隨著時(shí)間的推移,大多數(shù)數(shù)據(jù)都會(huì)被緩存,這也意味著相比與數(shù)據(jù)庫(kù),查詢語(yǔ)句會(huì)更多地從 memcached 中得到數(shù)據(jù)行。如果數(shù)據(jù)是相當(dāng)靜態(tài)的,我們可

以設(shè)置一個(gè)較長(zhǎng)的緩存時(shí)間。

基于行的緩存模式對(duì)下面這種搜索情況特別有用:數(shù)據(jù)集本身很大或是數(shù)據(jù)集是從多張表中得到,而數(shù)據(jù)集取決于查詢的輸入?yún)?shù)但是查詢的結(jié)果集之間的有重復(fù)部分。

比如,如果你有用戶 A , B , C , D , E 的數(shù)據(jù)集。你去點(diǎn)擊一張顯示用戶 A , B , E 信息的頁(yè)面。首先, memcached 得到 3 個(gè)不同的鍵,每個(gè)對(duì)應(yīng)一個(gè)用戶去緩存中查找,全部未

命中。然后就到數(shù)據(jù)庫(kù)中用 SQL 查詢得到 3 個(gè)用戶的數(shù)據(jù)行,并緩存他們。

現(xiàn)在,你又去點(diǎn)擊另一張顯示顯示 C , D , E 信息的頁(yè)面。當(dāng)你去查找 memcached 時(shí), C , D 的數(shù)據(jù)并沒(méi)有被命中,但我們命中了 E 的數(shù)據(jù)。然后從數(shù)據(jù)庫(kù)得到 C , D 的行數(shù)據(jù),緩

存在 memcached 中。至此以后,無(wú)論這些用戶信息怎樣地排列組合,任何關(guān)于 A , B , C , D , E 信息的頁(yè)面都可以從 memcached 得到數(shù)據(jù)了。

3)緩存的不只是 SQL 數(shù)據(jù),可以緩存最終完成的部分顯示頁(yè)面,以節(jié)省CPU計(jì)算時(shí)間

例如正在制作一張顯示用戶信息的頁(yè)面,你可能得到一段關(guān)于用戶的信息(姓名,生日,家庭住址,簡(jiǎn)介),然后你可能會(huì)將 XML 格式的簡(jiǎn)介信息轉(zhuǎn)化為 HTML 格式或做其他的一些工

作。相比單獨(dú)存儲(chǔ)這些屬性,你可能更愿意存儲(chǔ)經(jīng)過(guò)渲染的數(shù)據(jù)塊。那時(shí)你就可以簡(jiǎn)單地取出被預(yù)處理后的 HTML 直接填充在頁(yè)面中,這樣節(jié)省了寶貴的 CPU 時(shí)間。

32、使用分層的緩存

memcached 可以高速處理大量的緩存數(shù)據(jù),但是還是要根據(jù)系統(tǒng)的情況考慮維護(hù)多層的緩存結(jié)構(gòu)。例如除了memcached緩存之外,還可以通過(guò)本地緩存(如ehcache、oscache等)建

立起多級(jí)緩存。例如,可以采用本地緩存緩存一些基本數(shù)據(jù),例如少量但訪問(wèn)頻繁的數(shù)據(jù)(如產(chǎn)品分類,連接信息,服務(wù)器狀態(tài)變量,應(yīng)用配置變量等),緩存這些數(shù)據(jù)并讓他們盡可能的

接近處理器是有意義的 , 這樣可以幫助減少生成頁(yè)面的時(shí)間,并且在 memcached 失效的情況下可以增加可靠性。

33、當(dāng)數(shù)據(jù)更新時(shí)需要更新緩存

用戶編輯了自己的信息,當(dāng)保存信息到數(shù)據(jù)庫(kù)時(shí),需要更新緩存中的數(shù)據(jù)或是簡(jiǎn)單地刪除老的數(shù)據(jù)。如果馬上更新數(shù)據(jù),要防止從數(shù)據(jù)庫(kù)讀取那些剛剛更新過(guò)的數(shù)據(jù)。當(dāng)用戶習(xí)慣性地重新

載入自己的用戶信息來(lái)確認(rèn)是否修改成功時(shí),數(shù)據(jù)將從緩存中直接取出,這時(shí)他們獲得了最新的數(shù)據(jù)。

34、模擬帶鎖的添加命令

如果你實(shí)在需要鎖,你可以通過(guò)“添加”命令模仿鎖的功能。盡管在未命中的情況下它不是那么有用,但如果你用它緩存平常的數(shù)據(jù)(應(yīng)用服務(wù)器池的元數(shù)據(jù))那還是有用的。

比如,你要更新鍵 A 。

1. 添加一個(gè) "lock:A" 的鍵,這個(gè)鍵有一個(gè)持續(xù)幾秒的過(guò)期時(shí)間(足夠長(zhǎng)以使你能完成計(jì)算和更新,也不要很長(zhǎng),因?yàn)槿绻i進(jìn)程掛了,這個(gè)鍵不會(huì)立即釋放)

2. 如果添加操作成功了,你就擁有了鎖:從緩存獲取鍵 A 的數(shù)據(jù);利用客戶端程序更改數(shù)據(jù);更新緩存鍵 A 的數(shù)據(jù);刪除鍵 "lock:A" 。如果你不需要立即再次更新,就讓它存活直到失效。

3. 如果添加操作失敗,說(shuō)明有人獲取了鎖。這時(shí)讓應(yīng)用做些合適的事,比如返回老數(shù)據(jù),等待后重試,或是其他的。

以上這些操作類似 MySQL 將 GET_LOCK 的 timeout 值設(shè)置成 0 。沒(méi)有辦法在 memcached 中通過(guò)互斥鎖模擬 GET_LOCK() 的 timeout 操作。

35、預(yù)熱你的緩存

如果你有一個(gè)很高訪問(wèn)率的站點(diǎn),并且你正想加入故障恢復(fù)功能或是其他全新的功能,你最終可能會(huì)碰到空緩存的問(wèn)題。一開始緩存是空的,然后一大群人點(diǎn)擊你的站點(diǎn),在填充緩存的過(guò)

程中,你的數(shù)據(jù)庫(kù)可能會(huì)承受不住壓力。為了解決這一問(wèn)題,你可以試試任何可行的方法來(lái) " 溫暖 " 你的Memcached。方法:可以寫一些腳本來(lái)緩存通用的頁(yè)面;也可以寫一個(gè)命令行工

具來(lái)填充緩存。你可以在高峰時(shí)刻在緩存里填充一些內(nèi)容。

參考網(wǎng)頁(yè):

http://shwangking-126-com.iteye.com/blog/284937