天天看點

Memcache 面試題

memcached是怎麼工作的?

Memcached的神奇來自兩階段哈希(two-stage hash)。Memcached就像一個巨大的、存儲了很多

memcached最大的優勢是什麼?

請仔細閱讀上面的問題(即memcached是如何工作的)。Memcached最大的好處就是它帶來了極佳的水準可擴充性,特别是在一個巨大的系統中。由于用戶端自己做了一次哈希,那麼我們很容易增加大量memcached到叢集中。memcached之間沒有互相通信,是以不會增加 memcached的負載;沒有多點傳播協定,不會網絡通信量爆炸(implode)。memcached的叢集很好用。記憶體不夠了?增加幾台 memcached吧;CPU不夠用了?再增加幾台吧;有多餘的記憶體?在增加幾台吧,不要浪費了。

memcached和MySQL的querycache相比,有什麼優缺點?

把memcached引入應用中,還是需要不少工作量的。MySQL有個使用友善的query cache,可以自動地緩存SQL查詢的結果,被緩存的SQL查詢可以被反複地快速執行。Memcached與之相比,怎麼樣呢?MySQL的query cache是集中式的,連接配接到該query cache的MySQL伺服器都會受益。

  • 當您修改表時,MySQL的query cache會立刻被重新整理(flush)。存儲一個memcached item隻需要很少的時間,但是當寫操作很頻繁時,MySQL的query cache會經常讓所有緩存資料都失效。
  • 在多核CPU上,MySQL的query cache會遇到擴充問題(scalability issues)。在多核CPU上,query cache會增加一個全局鎖(global lock), 由于需要重新整理更多的緩存資料,速度會變得更慢。
  • 在 MySQL的query cache中,我們是不能存儲任意的資料的(隻能是SQL查詢結果)。而利用memcached,我們可以搭建出各種高效的緩存。比如,可以執行多個獨立的查詢,建構出一個使用者對象(user object),然後将使用者對象緩存到memcached中。而query cache是SQL語句級别的,不可能做到這一點。在小的網站中,query cache會有所幫助,但随着網站規模的增加,query cache的弊将大于利。
  • query cache能夠利用的記憶體容量受到MySQL伺服器空閑記憶體空間的限制。給資料庫伺服器增加更多的記憶體來緩存資料,固然是很好的。但是,有了memcached,隻要您有空閑的記憶體,都可以用來增加memcached叢集的規模,然後您就可以緩存更多的資料。

memcached和伺服器的localcache(比如PHP的APC、mmap檔案等)相比,有什麼優缺點?

首先,local cache有許多與上面(query cache)相同的問題。local cache能夠利用的記憶體容量受到(單台)伺服器空閑記憶體空間的限制。不過,local cache有一點比memcached和query cache都要好,那就是它不但可以存儲任意的資料,而且沒有網絡存取的延遲。

  • local cache的資料查詢更快。考慮把highly common的資料放在local cache中吧。如果每個頁面都需要加載一些數量較少的資料,考慮把它們放在local cached吧。
  • local cache缺少集體失效(group invalidation)的特性。在memcached叢集中,删除或更新一個key會讓所有的觀察者覺察到。但是在local cache中, 我們隻能通知所有的伺服器重新整理cache(很慢,不具擴充性),或者僅僅依賴緩存逾時失效機制。
  • local cache面臨着嚴重的記憶體限制,這一點上面已經提到。

memcached的cache機制是怎樣的?

Memcached主要的cache機制是LRU(最近最少用)算法+逾時失效。當您存資料到memcached中,可以指定該資料在緩存中可以呆多久。如果memcached的記憶體不夠用了,過期的slabs會優先被替換,接着就輪到最老的未被使用的slabs。

memcached如何實作備援機制?

不實作!我們對這個問題感到很驚訝。Memcached應該是應用的緩存層。它的設計本身就不帶有任何備援機制。如果一個memcached節點失去了所有資料,您應該可以從資料源(比如資料庫)再次擷取到資料

memcached如何處理容錯的?

不處理!:) 在memcached節點失效的情況下,叢集沒有必要做任何容錯處理。如果發生了節點失效,應對的措施完全取決于使用者。節點失效時,下面列出幾種方案供您選擇:

  • 忽略它! 在失效節點被恢複或替換之前,還有很多其他節點可以應對節點失效帶來的影響。
  • 把失效的節點從節點清單中移除。做這個操作千萬要小心!在預設情況下(餘數式雜湊演算法),用戶端添加或移除節點,會導緻所有的緩存資料不可用!因為哈希參照的節點清單變化了,大部分key會因為哈希值的改變而被映射到(與原來)不同的節點上。
  • 啟動熱備節點,接管失效節點所占用的IP。這樣可以防止哈希紊亂(hashing chaos)。
  • 如果希望添加和移除節點,而不影響原先的哈希結果,可以使用一緻性雜湊演算法(consistent hashing)。您可以百度一下一緻性雜湊演算法。支援一緻性哈希的用戶端已經很成熟,而且被廣泛使用。去嘗試一下吧!
  • 兩次哈希(reshing)。當用戶端存取資料時,如果發現一個節點down了,就再做一次哈希(雜湊演算法與前一次不同),重新選擇另一個節點(需要注意的時,用戶端并沒有把down的節點從節點清單中移除,下次還是有可能先哈希到它)。如果某個節點時好時壞,兩次哈希的方法就有風險了,好的節點和壞的節點上都可能存在髒資料(stale data)。

memcached是如何做身份驗證的?

沒有身份認證機制!memcached是運作在應用下層的軟體(身份驗證應該是應用上層的職責)。memcached的用戶端和伺服器端之是以是輕量級的,部分原因就是完全沒有實作身份驗證機制。這樣,memcached可以很快地建立新連接配接,伺服器端也無需任何配置。

如果您希望限制通路,您可以使用防火牆,或者讓memcached監聽unix domain socket。

如何使用memcached的多線程是什麼?如何使用它們?

線程就是定律(threads rule)!在Steven Grimm和Facebook的努力下,memcached 1.2及更高版本擁有了多線程模式。多線程模式允許memcached能夠充分利用多個CPU,并在CPU之間共享所有的緩存資料。memcached使用一種簡單的鎖機制來保證資料更新操作的互斥。相比在同一個實體機器上運作多個memcached執行個體,這種方式能夠更有效地處理multi gets。

如果您的系統負載并不重,也許您不需要啟用多線程工作模式。如果您在運作一個擁有大規模硬體的、龐大的網站,您将會看到多線程的好處。

memcached能接受的key的最大長度是多少?(250bytes)

key的最大長度是250個字元。需要注意的是,250是memcached伺服器端内部的限制,如果您使用的用戶端支援”key的字首”或類似特性,那麼key(字首+原始key)的最大長度是可以超過250個字元的。我們推薦使用使用較短的key,因為可以節省記憶體和帶寬。

memcached對item的過期時間有什麼限制?(為什麼有30天的限制?)

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

memcached最大能存儲多大的單個item?(1Mbyte)

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中存取很大的資料…不要嘗試把巨大的網頁放到mencached中。把這樣大的資料結構load和unpack到記憶體中需要花費很長的時間,進而導緻您的網站性能反而不好。

為了讓memcached更有效地使用伺服器的記憶體,可以在各個伺服器上配置大小不等的緩存空間嗎?

Memcache用戶端僅根據雜湊演算法來決定将某個key存儲在哪個節點上,而不考慮節點的記憶體大小。是以,您可以在不同的節點上使用大小不等的緩存。

memcached是如何配置設定記憶體的?為什麼不用malloc/free!?究竟為什麼使用slab呢?

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

實際上,這是一個編譯時選項。預設會使用内部的slab配置設定器。您确實确實應該使用内建的slab配置設定器。最早的時候,memcached隻使用 malloc/free來管理記憶體。然而,這種方式不能與OS的記憶體管理以前很好地工作。反複地malloc/free造成了記憶體碎片,OS最終花費大量的時間去查找連續的記憶體塊來滿足malloc的請求,而不是運作memcached程序。如果您不同意,當然可以使用malloc!隻是不要在郵件清單中抱怨啊:)

slab配置設定器就是為了解決這個問題而生的。記憶體被配置設定并劃分成chunks,一直被重複使用。因為記憶體被劃分成大小不等的slabs,如果item 的大小與被選擇存放它的slab不是很合适的話,就會浪費一些記憶體。Steven Grimm正在這方面已經做出了有效的改進。

memcached能保證資料存儲的原子性嗎?

所有的被發送到memcached的單個指令是完全原子的。如果您針對同一份資料同時發送了一個set指令和一個get指令,它們不會影響對方。它們将被串行化、先後執行。即使在多線程模式,所有的指令都是原子的,除非程式有bug:)

指令序列不是原子的。如果您通過get指令擷取了一個item,修改了它,然後想把它set回memcached,我們不保證這個item沒有被其他程序(process,未必是作業系統中的程序)操作過。在并發的情況下,您也可能覆寫了一個被其他程序set的item。

memcached 1.2.5以及更高版本,提供了gets和cas指令,它們可以解決上面的問題。如果您使用gets指令查詢某個key的item,memcached會給您傳回該item目前值的唯一辨別。如果您覆寫了這個item并想把它寫回到memcached中,您可以通過cas指令把那個唯一辨別一起發送給 memcached。如果該item存放在memcached中的唯一辨別與您提供的一緻,您的寫操作将會成功。如果另一個程序在這期間也修改了這個 item,那麼該item存放在memcached中的唯一辨別将會改變,您的寫操作就會失敗。

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

某人在set存儲memecache資料時候,将 $expire 設定為100天,發現設定的key總是擷取不到值?

memcache預設過期時間是30天,過期時間用秒為機關或時間戳為機關,前一種情況秒數不能超過60×60×24×30(30天時間的秒數);如果失效的值大于這個值, 服務端會将其作為一個真實的Unix時間戳來處理而不是自目前時間的偏移。如果過期時間設定為0,表示永不過期,但也不是相對的,有可能因為服務端為了給其他新的元素配置設定空間而被LRU算法删除。

繼續閱讀