史上最全memcached面试26题和答案
Memcached是什么,有什么作用?
Memcached是一個開源的,高性能的內存綬存軟件,從名稱上看Mem就是內存的意思,而Cache就是緩存的意思。Memcached的作用:通過在事先規劃好的內存空間中臨時綬存數據庫中的各類數據,以達到減少業務對數據庫的直接高并發訪問,從而達到提升數據庫的訪問性能,加速網站集群動態應用服務的能力。
?
Memcached服務在企業集群架構中有哪些應用場景?
一、作為數據庫的前端緩存應用
a、完整緩存(易),靜態緩存
例如:商品分類(京東),以及商品信息,可事先放在內存里,然后再對外提供數據訪問,這種先放到內存,我們稱之為預熱,(先把數據存緩存中),用戶訪問時可以只讀取memcached緩存,不讀取數據庫了。
b、執點緩存(難)
需要前端web程序配合,只緩存熱點的數據,即緩存經常被訪問的數據。
先預熱數據庫里的基礎數據,然后在動態更新,選讀取緩存,如果緩存里沒有對應的數據,程序再去讀取數據庫,然后程序把讀取的新數據放入緩存存儲。
特殊說明 :
1、如果碰到電商秒殺等高并發的業務,一定要事先預熱,或者其它思想實現,例如:稱殺只是獲取資格,而不是瞬間秒殺到手商品。
那么什么是獲取資格?
就是在數據庫中,把0標成1.就有資格啦。再慢慢的去領取商品訂單。因為秒殺過程太長會占用服務器資源。
2、如果數據更新,同時觸發緩存更新,防止給用戶過期數據。
c、對于持久化緩存存儲系統,例如:redis,可以替代一部分數據庫的存儲,一些簡單的數據業務,投票,統計,好友關注,商品分類等。nosql= not only sql
二、作業集群的session會話共享存儲。
3、Memcached服務在不同企業業務應用場景中的工作流程
a、當web程序需要訪問后端數據庫獲取數據時會優先訪問Memcached內存緩存,如果緩存中有數據就直接獲取返回前端服務及用戶,如果沒有數據(沒有命中),在由程序請求后端的數據庫服務器,獲取到對應的數據后,除了返回給前端服務及用戶數據外,還會把數據放到Memcached內存中進行緩存,等待下次請求被訪問,Memcache內存始終是數據庫的擋箭牌,從而大大的減輕數據庫的訪問壓力,提高整個網站架構的響應速度,提升了用戶體驗。
b、當程序更新,修改或刪除數據庫中已有的數據時,會同時發送請求通知Memcached已經緩存的同一個ID內容的舊數據失效,從而保證Memcache中數據和數據庫中的數據一致。
如果在高并發場合,除了通知Memcached過程的緩存失效外,還會通過相關機制,使得在用戶訪問新數據前,通過程序預先把更新過的數據推送到memcache中緩存起來,這樣可以減少數據庫的訪問壓力,提升Memcached中緩存命中率。
c、數據庫插件可以再寫入更新數據庫后,自動拋給MC緩存起來,自身不Cache.
?
Memcached服務分布式集群如何實現?
特殊說明:Memcached集群和web服務集群是不一樣的,所有Memcached的數據總和才是數據庫的數據。每臺Memcached都是部分數據。
(一臺memcached的數據,就是一部分mysql數據庫的數據)
a、程序端實現
程序加載所有mc的ip列表,通過對key做hash (一致性哈希算法)
例如:web1 (key)===>對應A,B,C,D,E,F,G…..若干臺服務器。(通過哈希算法實現)
b、負載均衡器
通過對key做hash (一致性哈希算法)
一致哈希算法的目的是不但保證每個對象只請求一個對應的服務器,而且當節點宕機,緩存服務器的更新重新分配比例降到最低。
Memcached服務特點及工作原理是什么?
a、完全基于內存緩存的
b、節點之間相互獨立
c、C/S模式架構,C語言編寫,總共2000行代碼。
d、異步I/O 模型,使用libevent作為事件通知機制。
e、被緩存的數據以key/value鍵值對形式存在的。
f、全部數據存放于內存中,無持久性存儲的設計,重啟服務器,內存里的數據會丟失。
g、當內存中緩存的數據容量達到啟動時設定的內存值時,就自動使用LRU算法刪除過期的緩存數據。
h、可以對存儲的數據設置過期時間,這樣過期后的數據自動被清除,服務本身不會監控過期,而是在訪問的時候查看key的時間戳,判斷是否過期。
j、memcache會對設定的內存進行分塊,再把塊分組,然后再提供服務。
簡述Memcached內存管理機制原理?
早期的Memcached內存管理方式是通過malloc的分配的內存,使用完后通過free來回收內存,這種方式容易產生內存碎片,并降低操作系統對內存的管理效率。加重操作系統內存管理器的負擔,最壞的情況下,會導致操作系統比memcached進程本身還慢,為了解決這個問題,Slab Allocation內存分配機制就延生了。
現在Memcached利用Slab Allocation機制來分配和管理內存。
Slab
Allocation機制原理是按照預先規定的大小,將分配給memcached的內存分割成特定長度的內存塊(chunk),再把尺寸相同的內存塊,分成組
(chunks slab class),這些內存塊不會釋放,可以重復利用。
?
而且,slab allocator還有重復使用已分配的內存的目的。 也就是說,分配到的內存不會釋放,而是重復利用。
Slab Allocation的主要術語
Page
分配給Slab的內存空間,默認是1MB。分配給Slab之后根據slab的大小切分成chunk。
Chunk
用于緩存記錄的內存空間。
Slab
Class
特定大小的chunk的組。??
集群架構方面的問題
memcached是怎么工作的?
Memcached的神奇來自兩階段哈希(two-stage hash)。Memcached就像一個巨大的、存儲了很多 ,value>對的哈希表。通過key,可以存儲或查詢任意的數據。
客戶端可以把數據存儲在多臺memcached上。當查詢數據時,客戶端首先參考節點列表計算出key的哈希值(階段一哈希),進而選中一個節點;客戶端將請求發送給選中的節點,然后memcached節點通過一個內部的哈希算法(階段二哈希),查找真正的數據(item)。
memcached最大的優勢是什么?
Memcached最大的好處就是它帶來了極佳的水平可擴展性,特別是在一個巨大的系統中。由于客戶端自己做了一次哈希,那么我們很容易增加大量memcached到集群中。memcached之間沒有相互通信,因此不會增加 memcached的負載;沒有多播協議,不會網絡通信量爆炸(implode)。memcached的集群很好用。內存不夠了?增加幾臺 memcached吧;CPU不夠用了?再增加幾臺吧;有多余的內存?在增加幾臺吧,不要浪費了。
基于memcached的基本原則,可以相當輕松地構建出不同類型的緩存架構。除了這篇FAQ,在其他地方很容易找到詳細資料的。
memcached和MySQL的query
cache相比,有什么優缺點?
把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和服務器的local cache(比如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中,可以指定該數據在緩存中可以呆多久Which is forever,
or some time in the future。如果memcached的內存不夠用了,過期的slabs會優先被替換,接著就輪到最老的未被使用的slabs。
memcached如何實現冗余機制?
不實現!我們對這個問題感到很驚訝。Memcached應該是應用的緩存層。它的設計本身就不帶有任何冗余機制。如果一個memcached節點失去了所有數據,您應該可以從數據源(比如數據庫)再次獲取到數據。您應該特別注意,您的應用應該可以容忍節點的失效。不要寫一些糟糕的查詢代碼,寄希望于 memcached來保證一切!如果您擔心節點失效會大大加重數據庫的負擔,那么您可以采取一些辦法。比如您可以增加更多的節點(來減少丟失一個節點的影響),熱備節點(在其他節點down了的時候接管IP),等等。
memcached如何處理容錯的?
不處理!在memcached節點失效的情況下,集群沒有必要做任何容錯處理。如果發生了節點失效,應對的措施完全取決于用戶。節點失效時,下面列出幾種方案供您選擇:
* 忽略它! 在失效節點被恢復或替換之前,還有很多其他節點可以應對節點失效帶來的影響。
* 把失效的節點從節點列表中移除。做這個操作千萬要小心!在默認情況下(余數式哈希算法),客戶端添加或移除節點,會導致所有的緩存數據不可用!因為哈希參照的節點列表變化了,大部分key會因為哈希值的改變而被映射到(與原來)不同的節點上。
* 啟動熱備節點,接管失效節點所占用的IP。這樣可以防止哈希紊亂(hashing chaos)。
* 如果希望添加和移除節點,而不影響原先的哈希結果,可以使用一致性哈希算法(consistent hashing)。您可以百度一下一致性哈希算法。支持一致性哈希的客戶端已經很成熟,而且被廣泛使用。去嘗試一下吧!
* 兩次哈希(reshing)。當客戶端存取數據時,如果發現一個節點down了,就再做一次哈希(哈希算法與前一次不同),重新選擇另一個節點(需要注意的時,客戶端并沒有把down的節點從節點列表中移除,下次還是有可能先哈希到它)。如果某個節點時好時壞,兩次哈希的方法就有風險了,好的節點和壞的節點上都可能存在臟數據(stale data)。
如何將memcached中item批量導入導出?
您不應該這樣做!Memcached是一個非阻塞的服務器。任何可能導致memcached暫停或瞬時拒絕服務的操作都應該值得深思熟慮。向 memcached中批量導入數據往往不是您真正想要的!想象看,如果緩存數據在導出導入之間發生了變化,您就需要處理臟數據了;
如果緩存數據在導出導入之間過期了,您又怎么處理這些數據呢?
因此,批量導出導入數據并不像您想象中的那么有用。不過在一個場景倒是很有用。如果您有大量的從不變化的數據,并且希望緩存很快熱(warm)起來,批量導入緩存數據是很有幫助的。雖然這個場景并不典型,但卻經常發生,因此我們會考慮在將來實現批量導出導入的功能。
如果一個memcached節點down了讓您很痛苦,那么您還會陷入其他很多麻煩。您的系統太脆弱了。您需要做一些優化工作。比如處理”驚群”問題(比如 memcached節點都失效了,反復的查詢讓您的數據庫不堪重負…這個問題在FAQ的其他提到過),或者優化不好的查詢。記住,Memcached 并不是您逃避優化查詢的借口。
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在這里花了大部分時間)可以運行在多線程模式下。memcached內部對數據的操作是基于很多全局鎖的(因此這部分工作不是多線程的)。未來對多線程模式的改進,將移除大量的全局鎖,提高memcached在負載極高的場景下的性能。
memcached能接受的key的最大長度是多少?
key的最大長度是250個字符。需要注意的是,250是memcached服務器端內部的限制,如果您使用的客戶端支持”key的前綴”或類似特性,那么key(前綴+原始key)的最大長度是可以超過250個字符的。我們推薦使用使用較短的key,因為可以節省內存和帶寬。
memcached對item的過期時間有什么限制?
過期時間最大可以達到30天。memcached把傳入的過期時間(時間段)解釋成時間點后,一旦到了這個時間點,memcached就把item置為失效狀態。這是一個簡單但obscure的機制。
memcached最大能存儲多大的單個item?
1MB。如果你的數據大于1MB,可以考慮在客戶端壓縮或拆分到多個key中。
為什么單個item的大小被限制在1M byte之內?
啊…這是一個大家經常問的問題!
簡單的回答:因為內存分配器的算法就是這樣的。
詳細的回答:Memcached的內存存儲引擎(引擎將來可插拔…),使用slabs來管理內存。內存被分成大小不等的slabs chunks(先分成大小相等的slabs,然后每個slab被分成大小相等chunks,不同slab的chunk大小是不相等的)。chunk的大小依次從一個最小數開始,按某個因子增長,直到達到最大的可能值。
memcached能夠更有效地使用內存嗎?
Memcache客戶端僅根據哈希算法來決定將某個key存儲在哪個節點上,而不考慮節點的內存大小。因此,您可以在不同的節點上使用大小不等的緩存。但是一般都是這樣做的:擁有較多內存的節點上可以運行多個memcached實例,每個實例使用的內存跟其他節點上的實例相同。
什么是二進制協議,我該關注嗎?
關于二進制最好的信息當然是二進制協議規范:
二進制協議嘗試為端提供一個更有效的、可靠的協議,減少客戶端/服務器端因處理協議而產生的CPU時間。
根據Facebook的測試,解析ASCII協議是memcached中消耗CPU時間最多的環節。所以,我們為什么不改進ASCII協議呢?
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中的唯一標識將會改變,您的寫操作就會失敗
?如何實現集群中的session共享存儲?
Session是運行在一臺服務器上的,所有的訪問都會到達我們的唯一服務器上,這樣我們可以根據客戶端傳來的sessionID,來獲取session,或在對應Session不存在的情況下(session 生命周期到了/用戶第一次登錄),創建一個新的Session;但是,如果我們在集群環境下,假設我們有兩臺服務器A,B,用戶的請求會由Nginx服務器進行轉發(別的方案也是同理),用戶登錄時,Nginx將請求轉發至服務器A上,A創建了新的session,并將SessionID返回給客戶端,用戶在瀏覽其他頁面時,客戶端驗證登錄狀態,Nginx將請求轉發至服務器B,由于B上并沒有對應客戶端發來sessionId的session,所以會重新創建一個新的session,并且再將這個新的sessionID返回給客戶端,這樣,我們可以想象一下,用戶每一次操作都有1/2的概率進行再次的登錄,這樣不僅對用戶體驗特別差,還會讓服務器上的session激增,加大服務器的運行壓力。
為了解決集群環境下的seesion共享問題,共有4種解決方案:
1.粘性session
粘性session是指Ngnix每次都將同一用戶的所有請求轉發至同一臺服務器上,即將用戶與服務器綁定。
2.服務器session復制
即每次session發生變化時,創建或者修改,就廣播給所有集群中的服務器,使所有的服務器上的session相同。
3.session共享
緩存session,使用redis, memcached。
4.session持久化
將session存儲至數據庫中,像操作數據一樣才做session。
memcached與redis的區別?
1、Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。而memcache只支持簡單數據類型,需要客戶端自己處理復雜對象
2、Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用(PS:持久化在rdb、aof)。
3、由于Memcache沒有持久化機制,因此宕機所有緩存數據失效。Redis配置為持久化,宕機重啟后,將自動加載宕機時刻的數據到緩存系統中。具有更好的災備機制。
4、Memcache可以使用Magent在客戶端進行一致性hash做分布式。Redis支持在服務器端做分布式(PS:Twemproxy/Codis/Redis-cluster多種分布式實現方式)
5、Memcached的簡單限制就是鍵(key)和Value的限制。最大鍵長為250個字符。可以接受的儲存數據不能超過1MB(可修改配置文件變大),因為這是典型slab 的最大值,不適合虛擬機使用。而Redis的Key長度支持到512k。
6、Redis使用的是單線程模型,保證了數據按順序提交。Memcache需要使用cas保證數據一致性。CAS(Check and Set)是一個確保并發一致性的機制,屬于“樂觀鎖”范疇;原理很簡單:拿版本號,操作,對比版本號,如果一致就操作,不一致就放棄任何操作
cpu利用。由于Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比Memcached性能更 高。而在100k以上的數據中,Memcached性能要高于Redis 。
7、memcache內存管理:使用Slab Allocation。原理相當簡單,預先分配一系列大小固定的組,然后根據數據大小選擇最合適的塊存儲。避免了內存碎片。(缺點:不能變長,浪費了一定空間)memcached默認情況下下一個slab的最大值為前一個的1.25倍。
8、redis內存管理: Redis通過定義一個數組來記錄所有的內存分配情況, Redis采用的是包裝的malloc/free,相較于Memcached的內存 管理方法來說,要簡單很多。由于malloc 首先以鏈表的方式搜索已管理的內存中可用的空間分配,導致內存碎片比較多
你可能也喜歡:
總結
以上是生活随笔為你收集整理的史上最全memcached面试26题和答案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 史上最全java架构师技能图谱(上)
- 下一篇: 论文浅尝 | TEQUILA: 一种面向