最后更新時(shí)間 2009-04-10    更新人 dormando@rydia.net
這里收集了經(jīng)常被問到的關(guān)于memcached的問題

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">集群架構(gòu)方面的問題

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached是怎么工作的?

Memcached的神奇來自兩階段哈希(two-stage hash)。Memcached就像一個(gè)巨大的、存儲(chǔ)了很多<key,value>對(duì)的哈希表。通過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)通過一個(gè)內(nèi)部的哈希算法(階段二哈希),查找真正的數(shù)據(jù)(item)。

舉個(gè)列子,假設(shè)有3個(gè)客戶端1, 2, 3,3臺(tái)memcached A, B, C:
Client 1想把數(shù)據(jù)"barbaz"以key "foo"存儲(chǔ)。Client 1首先參考節(jié)點(diǎn)列表(A, B, C),計(jì)算key "foo"的哈希值,假設(shè)memcached B被選中。接著,Client 1直接connect到memcached B,通過key "foo"把數(shù)據(jù)"barbaz"存儲(chǔ)進(jìn)去。Client 2使用與Client 1相同的客戶端庫(意味著階段一的哈希算法相同),也擁有同樣的memcached列表(A, B, C)。
于是,經(jīng)過相同的哈希計(jì)算(階段一),Client 2計(jì)算出key "foo"在memcached B上,然后它直接請(qǐng)求memcached B,得到數(shù)據(jù)"barbaz"。
各種客戶端在memcached中數(shù)據(jù)的存儲(chǔ)形式是不同的(perl Storable, php serialize, java hibernate, JSON等)。一些客戶端實(shí)現(xiàn)的哈希算法也不一樣。但是,memcached服務(wù)器端的行為總是一致的。

最后,從實(shí)現(xiàn)的角度看,memcached是一個(gè)非阻塞的、基于事件的服務(wù)器程序。這種架構(gòu)可以很好地解決C10K problem ,并具有極佳的可擴(kuò)展性。

可以參考A Story of Caching ,這篇文章簡單解釋了客戶端與memcached是如何交互的。

memcached最大的優(yōu)勢是什么?

請(qǐng)仔細(xì)閱讀上面的問題(即memcached是如何工作的)。Memcached最大的好處就是它帶來了極佳的水平可擴(kuò)展性,特別是在一個(gè)巨大的系 統(tǒng)中。由于客戶端自己做了一次哈希,那么我們很容易增加大量memcached到集群中。memcached之間沒有相互通信,因此不會(huì)增加 memcached的負(fù)載;沒有多播協(xié)議,不會(huì)網(wǎng)絡(luò)通信量爆炸(implode)。memcached的集群很好用。內(nèi)存不夠了?增加幾臺(tái) memcached吧;CPU不夠用了?再增加幾臺(tái)吧;有多余的內(nèi)存?在增加幾臺(tái)吧,不要浪費(fèi)了。

基于memcached的基本原則,可以相當(dāng)輕松地構(gòu)建出不同類型的緩存架構(gòu)。除了這篇FAQ,在其他地方很容易找到詳細(xì)資料的。

看看下面的幾個(gè)問題吧,它們?cè)趍emcached、服務(wù)器的local cache和MySQL的query cache之間做了比較。這幾個(gè)問題會(huì)讓您有更全面的認(rèn)識(shí)。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached和MySQL的query cache相比,有什么優(yōu)缺點(diǎn)?

把memcached引入應(yīng)用中,還是需要不少工作量的。MySQL有個(gè)使用方便的query cache,可以自動(dòng)地緩存SQL查詢的結(jié)果,被緩存的SQL查詢可以被反復(fù)地快速執(zhí)行。Memcached與之相比,怎么樣呢?MySQL的query cache是集中式的,連接到該query cache的MySQL服務(wù)器都會(huì)受益。

  • 當(dāng)您修改表時(shí),MySQL的query cache會(huì)立刻被刷新(flush)。存儲(chǔ)一個(gè)memcached item只需要很少的時(shí)間,但是當(dāng)寫操作很頻繁時(shí),MySQL的query cache會(huì)經(jīng)常讓所有緩存數(shù)據(jù)都失效。
  • 在多核CPU上,MySQL的query cache會(huì)遇到擴(kuò)展問題(scalability issues)。在多核CPU上,query cache會(huì)增加一個(gè)全局鎖(global lock), 由于需要刷新更多的緩存數(shù)據(jù),速度會(huì)變得更慢。
  • 在MySQL的query cache中,我們是不能存儲(chǔ)任意的數(shù)據(jù)的(只能是SQL查詢結(jié)果)。而利用memcached,我們可以搭建出各種高效的緩存。比如,可以執(zhí)行多個(gè)獨(dú)立 的查詢,構(gòu)建出一個(gè)用戶對(duì)象(user object),然后將用戶對(duì)象緩存到memcached中。而query cache是SQL語句級(jí)別的,不可能做到這一點(diǎn)。在小的網(wǎng)站中,query cache會(huì)有所幫助,但隨著網(wǎng)站規(guī)模的增加,query cache的弊將大于利。
  • query cache能夠利用的內(nèi)存容量受到MySQL服務(wù)器空閑內(nèi)存空間的限制。給數(shù)據(jù)庫服務(wù)器增加更多的內(nèi)存來緩存數(shù)據(jù),固然是很好的。但是,有了memcached,只要您有空閑的內(nèi)存,都可以用來增加memcached集群的規(guī)模,然后您就可以緩存更多的數(shù)據(jù)。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached和服務(wù)器的local cache(比如PHP的APC、mmap文件等)相比,有什么優(yōu)缺點(diǎn)?

首先,local cache有許多與上面(query cache)相同的問題。local cache能夠利用的內(nèi)存容量受到(單臺(tái))服務(wù)器空閑內(nèi)存空間的限制。不過,local cache有一點(diǎn)比memcached和query cache都要好,那就是它不但可以存儲(chǔ)任意的數(shù)據(jù),而且沒有網(wǎng)絡(luò)存取的延遲。

  • local cache的數(shù)據(jù)查詢更快。考慮把highly common的數(shù)據(jù)放在local cache中吧。如果每個(gè)頁面都需要加載一些數(shù)量較少的數(shù)據(jù),考慮把它們放在local cached吧。
  • local cache缺少集體失效(group invalidation)的特性。在memcached集群中,刪除或更新一個(gè)key會(huì)讓所有的觀察者覺察到。但是在local cache中, 我們只能通知所有的服務(wù)器刷新cache(很慢,不具擴(kuò)展性),或者僅僅依賴緩存超時(shí)失效機(jī)制。
  • local cache面臨著嚴(yán)重的內(nèi)存限制,這一點(diǎn)上面已經(jīng)提到。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">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)存不夠用了,過期的slabs會(huì)優(yōu)先被替換,接著就輪到最老的未被使用的slabs。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached如何實(shí)現(xiàn)冗余機(jī)制?
不 實(shí)現(xiàn)!我們對(duì)這個(gè)問題感到很驚訝。Memcached應(yīng)該是應(yīng)用的緩存層。它的設(shè)計(jì)本身就不帶有任何冗余機(jī)制。如果一個(gè)memcached節(jié)點(diǎn)失去了所有 數(shù)據(jù),您應(yīng)該可以從數(shù)據(jù)源(比如數(shù)據(jù)庫)再次獲取到數(shù)據(jù)。您應(yīng)該特別注意,您的應(yīng)用應(yīng)該可以容忍節(jié)點(diǎn)的失效。不要寫一些糟糕的查詢代碼,寄希望于 memcached來保證一切!如果您擔(dān)心節(jié)點(diǎn)失效會(huì)大大加重?cái)?shù)據(jù)庫的負(fù)擔(dān),那么您可以采取一些辦法。比如您可以增加更多的節(jié)點(diǎn)(來減少丟失一個(gè)節(jié)點(diǎn)的影 響),熱備節(jié)點(diǎn)(在其他節(jié)點(diǎn)down了的時(shí)候接管IP),等等。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached如何處理容錯(cuò)的?
不處理!:) 在memcached節(jié)點(diǎn)失效的情況下,集群沒有必要做任何容錯(cuò)處理。如果發(fā)生了節(jié)點(diǎn)失效,應(yīng)對(duì)的措施完全取決于用戶。節(jié)點(diǎn)失效時(shí),下面列出幾種方案供您選擇:

  • 忽略它! 在失效節(jié)點(diǎn)被恢復(fù)或替換之前,還有很多其他節(jié)點(diǎn)可以應(yīng)對(duì)節(jié)點(diǎn)失效帶來的影響。
  • 把失效的節(jié)點(diǎn)從節(jié)點(diǎn)列表中移除。做這個(gè)操作千萬要小心!在默認(rèn)情況下(余數(shù)式哈希算法),客戶端添加或移除節(jié)點(diǎn),會(huì)導(dǎo)致所有的緩存數(shù)據(jù)不可用!因?yàn)楣⒄盏墓?jié)點(diǎn)列表變化了,大部分key會(huì)因?yàn)楣V档母淖兌挥成涞剑ㄅc原來)不同的節(jié)點(diǎn)上。
  • 啟動(dòng)熱備節(jié)點(diǎn),接管失效節(jié)點(diǎn)所占用的IP。這樣可以防止哈希紊亂(hashing chaos)。
  • 如果希望添加和移除節(jié)點(diǎn),而不影響原先的哈希結(jié)果,可以使用一致性哈希算法(consistent hashing)。您可以百度一下一致性哈希算法。支持一致性哈希的客戶端已經(jīng)很成熟,而且被廣泛使用。去嘗試一下吧!
  • 兩次哈希(reshing)。當(dāng)客戶端存取數(shù)據(jù)時(shí),如果發(fā)現(xiàn)一個(gè)節(jié)點(diǎn)down了,就再做一次哈希(哈希算法與前一次不同),重新選擇另一個(gè)節(jié)點(diǎn) (需要注意的時(shí),客戶端并沒有把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)。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">如何將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)入 之間過期了,您又怎么處理這些數(shù)據(jù)呢?

因此,批量導(dǎo)出導(dǎo)入數(shù)據(jù)并不像您想象中的那么有用。不過在一個(gè)場景倒是很有用。如果您有大量的從不變化 的數(shù)據(jù),并且希望緩存很快熱(warm)起來,批量導(dǎo)入緩存數(shù)據(jù)是很有幫助的。雖然這個(gè)場景并不典型,但卻經(jīng)常發(fā)生,因此我們會(huì)考慮在將來實(shí)現(xiàn)批量導(dǎo)出導(dǎo)入的功能。

Steven Grimm,一如既往地,,在郵件列表中給出了另一個(gè)很好的例子:http://lists.danga.com/pipermail/memcached/2007-July/004802.html

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">但是我確實(shí)需要把memcached中的item批量導(dǎo)出導(dǎo)入,怎么辦??

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

如果一個(gè)memcached節(jié)點(diǎn)down了讓您很痛苦,那么您還會(huì)陷入其他很多麻煩。您的系統(tǒng)太脆弱了。您需要做一些優(yōu)化工作。比如處理"驚群"問 題(比如 memcached節(jié)點(diǎn)都失效了,反復(fù)的查詢讓您的數(shù)據(jù)庫不堪重負(fù)...這個(gè)問題在FAQ的其他提到過),或者優(yōu)化不好的查詢。記住,Memcached 并不是您逃避優(yōu)化查詢的借口。

如果您的麻煩僅僅是重新生成緩存數(shù)據(jù)需要消耗很長時(shí)間(15秒到超過5分鐘),您可以考慮重新使用數(shù)據(jù)庫。這里給出一些提示:

  • 使用MogileFS(或者CouchDB等類似的軟件)在存儲(chǔ)item。把item計(jì)算出來并dump到磁盤上。MogileFS可以很方便地 覆寫item,并提供快速地訪問。.您甚至可以把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í)索引來加快查 詢...key被動(dòng)地失效,批量刪除失效的key,等等。

上面的方法都可以引入memcached,在重啟memcached的時(shí)候仍然提供很好的性能。由于您不需要當(dāng)心"hot"的item被 memcached LRU算法突然淘汰,用戶再也不用花幾分鐘來等待重新生成緩存數(shù)據(jù)(當(dāng)緩存數(shù)據(jù)突然從內(nèi)存中消失時(shí)),因此上面的方法可以全面提高性能。

關(guān)于這些方法的細(xì)節(jié),詳見博客:http://dormando.livejournal.com/495593.html

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached是如何做身份驗(yàn)證的?
沒有身份認(rèn)證機(jī)制!memcached是運(yùn)行在應(yīng)用下層的軟件(身份驗(yàn)證應(yīng)該是應(yīng)用上層的職責(zé))。memcached的客戶端和服務(wù)器端之所以是輕量級(jí)的,部分原因就是完全沒有實(shí)現(xiàn)身份驗(yàn)證機(jī)制。這樣,memcached可以很快地創(chuàng)建新連接,服務(wù)器端也無需任何配置。

如果您希望限制訪問,您可以使用防火墻,或者讓memcached監(jiān)聽unix domain socket。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached的多線程是什么?如何使用它們?
線 程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本擁有了多線程模式。多線程模式允許memcached能夠充分利用多個(gè)CPU,并在CPU之間共享所有的緩存數(shù)據(jù)。memcached使 用一種簡單的鎖機(jī)制來保證數(shù)據(jù)更新操作的互斥。相比在同一個(gè)物理機(jī)器上運(yùn)行多個(gè)memcached實(shí)例,這種方式能夠更有效地處理multi gets。

如果您的系統(tǒng)負(fù)載并不重,也許您不需要啟用多線程工作模式。如果您在運(yùn)行一個(gè)擁有大規(guī)模硬件的、龐大的網(wǎng)站,您將會(huì)看到多線程的好處。

更多信息請(qǐng)參見:http://code.sixapart.com/svn/memcached/trunk/server/doc/threads.txt

簡 單地總結(jié)一下:命令解析(memcached在這里花了大部分時(shí)間)可以運(yùn)行在多線程模式下。memcached內(nèi)部對(duì)數(shù)據(jù)的操作是基于很多全局鎖的(因 此這部分工作不是多線程的)。未來對(duì)多線程模式的改進(jìn),將移除大量的全局鎖,提高memcached在負(fù)載極高的場景下的性能。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached能接受的key的最大長度是多少?
key 的最大長度是250個(gè)字符。需要注意的是,250是memcached服務(wù)器端內(nèi)部的限制,如果您使用的客戶端支持"key的前綴"或類似特性,那么 key(前綴+原始key)的最大長度是可以超過250個(gè)字符的。我們推薦使用使用較短的key,因?yàn)榭梢怨?jié)省內(nèi)存和帶寬。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached對(duì)item的過期時(shí)間有什么限制?

過期時(shí)間最大可以達(dá)到30天。memcached把傳入的過期時(shí)間(時(shí)間段)解釋成時(shí)間點(diǎn)后,一旦到了這個(gè)時(shí)間點(diǎn),memcached就把item置為失效狀態(tài)。這是一個(gè)簡單但obscure的機(jī)制。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached最大能存儲(chǔ)多大的單個(gè)item?
1MB。如果你的數(shù)據(jù)大于1MB,可以考慮在客戶端壓縮或拆分到多個(gè)key中。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">為什么單個(gè)item的大小被限制在1M byte之內(nèi)?
啊...這是一個(gè)大家經(jīng)常問的問題!

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

詳 細(xì)的回答:Memcached的內(nèi)存存儲(chǔ)引擎(引擎將來可插拔...),使用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è)置了較小的因子和較大的最大值,會(huì)需要更多的內(nèi)存。

還有其他原因使得您不要這樣向memcached中存取很大的數(shù)據(jù)...不要嘗試把巨大的網(wǎng)頁放到mencached中。把這樣大的數(shù)據(jù)結(jié)構(gòu)load和unpack到內(nèi)存中需要花費(fèi)很長的時(shí)間,從而導(dǎo)致您的網(wǎng)站性能反而不好。

如果您確實(shí)需要存儲(chǔ)大于1MB的數(shù)據(jù),你可以修改slabs.c:POWER_BLOCK的值,然后重新編譯memcached;或者使用低效的malloc/free。其他的建議包括數(shù)據(jù)庫、MogileFS等。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">我可以在不同的memcached節(jié)點(diǎn)上使用大小不等的緩存空間嗎?這么做之后,memcached能夠更有效地使用內(nèi)存嗎?
Memcache 客戶端僅根據(jù)哈希算法來決定將某個(gè)key存儲(chǔ)在哪個(gè)節(jié)點(diǎn)上,而不考慮節(jié)點(diǎn)的內(nèi)存大小。因此,您可以在不同的節(jié)點(diǎn)上使用大小不等的緩存。但是一般都是這樣做 的:擁有較多內(nèi)存的節(jié)點(diǎn)上可以運(yùn)行多個(gè)memcached實(shí)例,每個(gè)實(shí)例使用的內(nèi)存跟其他節(jié)點(diǎn)上的實(shí)例相同。

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">什么是二進(jìn)制協(xié)議,我該關(guān)注嗎?
關(guān)于二進(jìn)制最好的信息當(dāng)然是二進(jìn)制協(xié)議規(guī)范:http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol

二進(jìn)制協(xié)議嘗試為端提供一個(gè)更有效的、可靠的協(xié)議,減少客戶端/服務(wù)器端因處理協(xié)議而產(chǎn)生的CPU時(shí)間。
根據(jù)Facebook的測試,解析ASCII協(xié)議是memcached中消耗CPU時(shí)間最多的環(huán)節(jié)。所以,我們?yōu)槭裁床桓倪M(jìn)ASCII協(xié)議呢?

在這個(gè)郵件列表的thread中可以找到一些舊的信息:http://lists.danga.com/pipermail/memcached/2007-July/004636.html

" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached的內(nèi)存分配器是如何工作的?為什么不適用malloc/free!?為何要使用slabs?
實(shí) 際上,這是一個(gè)編譯時(shí)選項(xiàng)。默認(rèn)會(huì)使用內(nèi)部的slab分配器。您確實(shí)確實(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的請(qǐng)求,而不是運(yùn)行memcached進(jìn)程。如果您不同意,當(dāng)然可以使用malloc!只是不要在郵件列表中 抱怨啊:)

slab分配器就是為了解決這個(gè)問題而生的。內(nèi)存被分配并劃分成chunks,一直被重復(fù)使用。因?yàn)閮?nèi)存被劃分成大小不等的 slabs,如果item的大小與被選擇存放它的slab不是很合適的話,就會(huì)浪費(fèi)一些內(nèi)存。Steven Grimm正在這方面已經(jīng)做出了有效的改進(jìn)。

郵件列表中有一些關(guān)于slab的改進(jìn)(power of n 還是 power of 2)和權(quán)衡方案:http://lists.danga.com/pipermail/memcached/2006-May/002163.html http://lists.danga.com/pipermail/memcached/2007-March/003753.html

如果您想使用malloc/free,看看它們工作地怎么樣,您可以在構(gòu)建過程中定義USE_SYSTEM_MALLOC。這個(gè)特性沒有經(jīng)過很好的測試,所以太不可能得到開發(fā)者的支持。

更多信息:http://code.sixapart.com/svn/memcached/trunk/server/doc/memory_management.txt


" src="/CuteSoft_Client/CuteEditor/Images/anchor.gif">memcached是原子的嗎?
當(dāng)然!好吧,讓我們來明確一下:
所有的被發(fā)送到memcached的單個(gè)命令是完全原子的。如果您針對(duì)同一份數(shù)據(jù)同時(shí)發(fā)送了一個(gè)set命令和一個(gè)get命令,它們不會(huì)影響對(duì)方。它們將被串行化、先后執(zhí)行。即使在多線程模式,所有的命令都是原子的,除非程序有bug:)
命令序列不是原子的。如果您通過get命令獲取了一個(gè)item,修改了它,然后想把它set回memcached,我們不保證這個(gè)item沒有被其他進(jìn)程(process,未必是操作系統(tǒng)中的進(jìn)程)操作過。在并發(fā)的情況下,您也可能覆寫了一個(gè)被其他進(jìn)程set的item。

memcached 1.2.5以及更高版本,提供了gets和cas命令,它們可以解決上面的問題。如果您使用gets命令查詢某個(gè)key的item,memcached會(huì) 給您返回該item當(dāng)前值的唯一標(biāo)識(shí)。如果您覆寫了這個(gè)item并想把它寫回到memcached中,您可以通過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ì)失敗。

通常,基于memcached中item的值來修改item,是一件棘手的事情。除非您很清楚自己在做什么,否則請(qǐng)不要做這樣的事情。