memcached面试专题
memcached 是怎么工作的?
Memcached 的神奇來(lái)自兩階段哈希(two-stage hash)。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)。
舉個(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,
通過(guò) key “foo”把數(shù)據(jù)”barbaz”存儲(chǔ)進(jìn)去。 Client 2 使用與 Client 1 相同的客戶端庫(kù)(意
味著階段一的哈希算法相同),也擁有同樣的 memcached 列表(A, B, C)。
于是,經(jīng)過(guò)相同的哈希計(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 ,這篇文章簡(jiǎn)單解釋了客戶端與 memcached 是如何交互的。
memcached 最大的優(yōu)勢(shì)是什么?
請(qǐng)仔細(xì)閱讀上面的問(wèn)題(即 memcached 是如何工作的)。Memcached 最大的好處就是它帶
來(lái)了極佳的水平可擴(kuò)展性,特別是在一個(gè)巨大的系統(tǒng)中。由于客戶端自己做了一次哈希,
那么我們很容易增加大量 memcached 到集群中。memcached 之間沒(méi)有相互通信,因此不
會(huì)增加 memcached 的負(fù)載;沒(méi)有多播協(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)建出不同類(lèi)型的緩存架構(gòu)。除了這篇
FAQ,在其他地方很容易找到詳細(xì)資料的。
看看下面的幾個(gè)問(wèn)題吧,它們?cè)?memcached、服務(wù)器的 local cache 和 MySQL 的 query
cache 之間做了比較。這幾個(gè)問(wèn)題會(huì)讓您有更全面的認(rèn)識(shí)。
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)寫(xiě)操作很頻繁時(shí),MySQL 的 query cache 會(huì)經(jīng)常讓所有緩存數(shù)據(jù)
都失效。 - 在多核 CPU 上,MySQL 的 query cache 會(huì)遇到擴(kuò)展問(wèn)題(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 語(yǔ)句級(jí)別的,不可能做到這一點(diǎn)。在小的網(wǎng)站中,query cache 會(huì)有所幫助,
但隨著網(wǎng)站規(guī)模的增加,query cache 的弊將大于利。 - 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ù)。
memcached 和服務(wù)器的 local cache(比如 PHP 的 APC、mmap 文件等)相比,有什么優(yōu)缺
點(diǎn)?
首先,local cache 有許多與上面(query cache)相同的問(wèn)題。local cache 能夠利用的內(nèi)存容量
受到(單臺(tái))服務(wù)器空閑內(nèi)存空間的限制。不過(guò),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 吧。 - local cache 缺少集體失效(group invalidation)的特性。在 memcached 集群中,刪除或更
新一個(gè) key 會(huì)讓所有的觀察者覺(jué)察到。但是在 local cache 中, 我們只能通知所有的服務(wù)器
刷新 cache(很慢,不具擴(kuò)展性),或者僅僅依賴緩存超時(shí)失效機(jī)制。 - local cache 面臨著嚴(yán)重的內(nèi)存限制,這一點(diǎn)上面已經(jīng)提到。
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。
memcached 如何實(shí)現(xiàn)冗余機(jī)制?
不實(shí)現(xiàn)!我們對(duì)這個(gè)問(wèn)題感到很驚訝。Memcached 應(yīng)該是應(yīng)用的緩存層。它的設(shè)計(jì)本身就
不帶有任何冗余機(jī)制。如果一個(gè) memcached 節(jié)點(diǎn)失去了所有數(shù)據(jù),您應(yīng)該可以從數(shù)據(jù)源
(比如數(shù)據(jù)庫(kù))再次獲取到數(shù)據(jù)。您應(yīng)該特別注意,您的應(yīng)用應(yīng)該可以容忍節(jié)點(diǎn)的失效。
不要寫(xiě)一些糟糕的查詢代碼,寄希望于 memcached 來(lái)保證一切!如果您擔(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),等等。
memcached 如何處理容錯(cuò)的?
不處理!😃 在 memcached 節(jié)點(diǎn)失效的情況下,集群沒(méi)有必要做任何容錯(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)失效帶來(lái)的影
響。 - 把失效的節(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档母淖兌挥成涞?#xff08;與原來(lái))不同的節(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í),客戶端并沒(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)。
如何將 memcached 中 item 批量導(dǎo)入導(dǎo)出?
您不應(yīng)該這樣做!Memcached 是一個(gè)非阻塞的服務(wù)器。任何可能導(dǎo)致 memcached 暫?;?br /> 瞬時(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ù)是很
有幫助的。雖然這個(gè)場(chǎng)景并不典型,但卻經(jīng)常發(fā)生,因此我們會(huì)考慮在將來(lái)實(shí)現(xiàn)批量導(dǎo)出
導(dǎo)入的功能。
Steven Grimm,一如既往地,,在郵件列表中給出了另一個(gè)很好的例子:
http://lists.danga.com/pipermail/memcached/2007-July/004802.html 。
我需要把 memcached 中的 item 批量導(dǎo)出導(dǎo)入,怎么辦?
好吧好吧。如果您需要批量導(dǎo)出導(dǎo)入,最可能的原因一般是重新生成緩存數(shù)據(jù)需要消耗很
長(zhǎng)的時(shí)間,或者數(shù)據(jù)庫(kù)壞了讓您飽受痛苦。
如果一個(gè) memcached 節(jié)點(diǎn) down 了讓您很痛苦,那么您還會(huì)陷入其他很多麻煩。您的系統(tǒng)
太脆弱了。您需要做一些優(yōu)化工作。比如處理”驚群”問(wèn)題(比如 memcached 節(jié)點(diǎn)都失效
了,反復(fù)的查詢讓您的數(shù)據(jù)庫(kù)不堪重負(fù)…這個(gè)問(wèn)題在 FAQ 的其他提到過(guò)),或者優(yōu)化不好的
查詢。記住,Memcached 并不是您逃避優(yōu)化查詢的借口。
如果您的麻煩僅僅是重新生成緩存數(shù)據(jù)需要消耗很長(zhǎng)時(shí)間(15 秒到超過(guò) 5 分鐘),您可以
考慮重新使用數(shù)據(jù)庫(kù)。這里給出一些提示: - 使用 MogileFS(或者 CouchDB 等類(lèi)似的軟件)在存儲(chǔ) item。把 item 計(jì)算出來(lái)并 dump 到
磁盤(pán)上。MogileFS 可以很方便地覆寫(xiě) 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,等等。
上面的方法都可以引入 memcached,在重啟 memcached 的時(shí)候仍然提供很好的性能。由
于您不需要當(dāng)心”hot”的 item 被 memcached LRU 算法突然淘汰,用戶再也不用花幾分鐘來(lái)
等待重新生成緩存數(shù)據(jù)(當(dāng)緩存數(shù)據(jù)突然從內(nèi)存中消失時(shí)),因此上面的方法可以全面提高
性能。
關(guān)于這些方法的細(xì)節(jié),詳見(jiàn)博客:http://dormando.livejournal.com/495593.html 。
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)聽(tīng) unix domain socket。
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)站,您將會(huì)看到多線程的好處。
簡(jiǎn)單地總結(jié)一下:命令解析(memcached 在這里花了大部分時(shí)間)可以運(yùn)行在多線程模式
下。memcached 內(nèi)部對(duì)數(shù)據(jù)的操作是基于很多全局鎖的(因此這部分工作不是多線程
的)。未來(lái)對(duì)多線程模式的改進(jìn),將移除大量的全局鎖,提高 memcached 在負(fù)載極高的場(chǎng)
景下的性能。
memcached 能接受的 key 的最大長(zhǎng)度是多少?
key 的最大長(zhǎng)度是 250 個(gè)字符。需要注意的是,250 是 memcached 服務(wù)器端內(nèi)部的限制,
如果您使用的客戶端支持”key 的前綴”或類(lèi)似特性,那么 key(前綴+原始 key)的最大長(zhǎng)度
是可以超過(guò) 250 個(gè)字符的。我們推薦使用使用較短的 key,因?yàn)榭梢怨?jié)省內(nèi)存和帶寬。
memcached 對(duì) item 的過(guò)期時(shí)間有什么限制?
過(guò)期時(shí)間最大可以達(dá)到 30 天。memcached 把傳入的過(guò)期時(shí)間(時(shí)間段)解釋成時(shí)間點(diǎn)
后,一旦到了這個(gè)時(shí)間點(diǎn),memcached 就把 item 置為失效狀態(tài)。這是一個(gè)簡(jiǎn)單但 obscure
的機(jī)制。
memcached 最大能存儲(chǔ)多大的單個(gè) item?
1MB。如果你的數(shù)據(jù)大于 1MB,可以考慮在客戶端壓縮或拆分到多個(gè) key 中。
為什么單個(gè) item 的大小被限制在 1M byte 之內(nèi)?
簡(jiǎn)單的回答:因?yàn)閮?nèi)存分配器的算法就是這樣的。
詳細(xì)的回答:Memcached 的內(nèi)存存儲(chǔ)引擎(引擎將來(lái)可插拔…),使用 slabs 來(lái)管理內(nèi)存。
內(nèi)存被分成大小不等的 slabs chunks(先分成大小相等的 slabs,然后每個(gè) slab 被分成大小
相等 chunks,不同 slab 的 chunk 大小是不相等的)。chunk 的大小依次從一個(gè)最小數(shù)開(kāi)始,
按某個(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ì)需要更多的內(nèi)存。
還有其他原因使得您不要這樣向 memcached 中存取很大的數(shù)據(jù)…不要嘗試把巨大的網(wǎng)頁(yè)放
到 mencached 中。把這樣大的數(shù)據(jù)結(jié)構(gòu) load 和 unpack 到內(nèi)存中需要花費(fèi)很長(zhǎng)的時(shí)間,從
而導(dǎo)致您的網(wǎng)站性能反而不好。
如果您確實(shí)需要存儲(chǔ)大于 1MB 的數(shù)據(jù),你可以修改 slabs.c:POWER_BLOCK 的值,然后重新
編譯 memcached;或者使用低效的 malloc/free。其他的建議包括數(shù)據(jù)庫(kù)、MogileFS 等。
我可以在不同的 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)存的節(jié)點(diǎn)上可以運(yùn)行多個(gè) memcached 實(shí)例,每個(gè)實(shí)例使用的內(nèi)存跟其他節(jié)點(diǎn)上
的實(shí)例相同。
總結(jié)
以上是生活随笔為你收集整理的memcached面试专题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用web-play开发web应用
- 下一篇: GA-H81M-DS2 触发-掉电-自动