掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
memcache是互聯(lián)網(wǎng)分層架構(gòu)中,使用最多的的KV緩存。面試的過程中,memcache相關(guān)的問題幾乎是必問的,關(guān)于memcache的面試提問,你能回答到哪一個層次呢?

江岸ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為成都創(chuàng)新互聯(lián)公司的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!
畫外音:很可能關(guān)乎,你拿到offer的薪酬檔位。
***類問題:知道不知道
這一類問題,考察用沒用過,知不知道,相對比較好回答。
關(guān)于memcache一些基礎(chǔ)特性,使用過的小伙伴基本都能回答出來:
面對這類封閉性的問題,一定要斬釘截鐵,毫無猶豫的給出回答。
第二類問題:為什么(why),什么(what)
這一類問題,考察對于一個工具,只停留在使用層面,還是有原理性的思考。
(1) memcache為什么不支持復(fù)雜數(shù)據(jù)結(jié)構(gòu)?為什么不支持持久化?
業(yè)務(wù)決定技術(shù)方案,mc的誕生,以“以服務(wù)的方式,而不是庫的方式管理KV內(nèi)存”為設(shè)計(jì)目標(biāo),它顛覆的是,KV內(nèi)存管理組件庫,復(fù)雜數(shù)據(jù)結(jié)構(gòu)與持久化并不是它的初衷。
當(dāng)然,用“顛覆”這個詞未必不合適,庫和服務(wù)各有使用場景,只是在分布式的環(huán)境下,服務(wù)的使用范圍更廣。設(shè)計(jì)目標(biāo),誕生背景很重要,這一定程度上決定了實(shí)現(xiàn)方案,就如redis的出現(xiàn),是為了有一個更好用,更多功能的緩存服務(wù)。
畫外音:我很喜歡問這個問題,大部分候選人面對這個沒有標(biāo)準(zhǔn)答案的問題,狀態(tài)可能是蒙圈。
(2) memcache是用什么技術(shù)實(shí)現(xiàn)key過期的?
懶淘汰(lazy expiration)。
(3) memcache為什么能保證運(yùn)行性能,且很少會出現(xiàn)內(nèi)存碎片?
提前分配內(nèi)存。
(4) memcache為什么要使用非阻塞IO復(fù)用網(wǎng)絡(luò)模型,使用監(jiān)聽線程/工作線程的多線程模型,有什么優(yōu)缺點(diǎn)?
目的是提高吞吐量。
多線程能夠充分的利用多核,但會帶來一些鎖沖突。
面對這類半開放的問題,有些并沒有標(biāo)準(zhǔn)答案,一定要回答出自己的思考和見解。
第三類問題:怎么做(how) | 文本剛開始
這一類問題,探測候選人理解得有多透,掌握得有多細(xì),對技術(shù)有多刨根究底。
畫外音:所謂“好奇心”,真的很重要,只想要“一份工作”的技術(shù)人很難有這種好奇心。
(1) memcache是什么實(shí)現(xiàn)內(nèi)存管理,以減小內(nèi)存碎片,是怎么實(shí)現(xiàn)分配內(nèi)存的?
開講之前,先解釋幾個非常重要的概念:
畫外音:為了避免復(fù)雜性,本文先不引入page的概念了。
如上圖所示,一系列slab,分別管理128B,256B,512B…的chunk內(nèi)存單元。
將上圖中管理128B的slab0放大:
能夠發(fā)現(xiàn)slab中的一些核心數(shù)據(jù)結(jié)構(gòu)是:
畫外音:其實(shí)還有l(wèi)ru_list。
(2) 假如用戶要存儲一個100B的item,是如何找到對應(yīng)的可用chunk的呢?
會從最接近item大小的slab的chunk[]中,通過free_chunk_list快速找到對應(yīng)的chunk,如上圖所示,與item大小最接近的chunk是128B。
(3) 為什么不會出現(xiàn)內(nèi)存碎片呢?
拿到一個128B的chunk,去存儲一個100B的item,余下的28B不會再被其他的item所使用,即:實(shí)際上浪費(fèi)了存儲空間,來減少內(nèi)存碎片,保證訪問的速度。
畫外音:理論上,內(nèi)存碎片幾乎不存在。
(4) memcache通過slab,chunk,free_chunk_list來快速分配內(nèi)存,存儲用戶的item,那它又是如何快速實(shí)現(xiàn)key的查找的呢?
沒有什么特別算法:
用最樸素的方式,實(shí)現(xiàn)key的快速查找。
(5) 隨著item的個數(shù)不斷增多,hash沖突越來越大,hash表如何保證查詢效率呢?
當(dāng)item總數(shù)達(dá)到hash表長度的1.5倍時,hash表會動態(tài)擴(kuò)容,rehash將數(shù)據(jù)重新分布,以保證查找效率不會不斷降低。
(6) 擴(kuò)展hash表之后,同一個key在新舊hash表內(nèi)的位置會發(fā)生變化,如何保證數(shù)據(jù)的一致性,以及如何保證遷移過程服務(wù)的可用性呢(肯定不能加一把大鎖,遷移完成數(shù)據(jù),再重新服務(wù)吧)?
哈希表擴(kuò)展,數(shù)據(jù)遷移是一個耗時的操作,會有一個專門的線程來實(shí)施,為了避免大鎖,采用的是“分段遷移”的策略。
當(dāng)item數(shù)量達(dá)到閾值時,遷移線程會分段遷移,對hash表中的一部分桶進(jìn)行加鎖,遷移數(shù)據(jù),解鎖:
(7) 新的問題來了,對于已經(jīng)存在與舊hash表中的item,可以通過上述方式遷移,那么在item遷移的過程中,如果有新的item插入,是應(yīng)該插入舊hash表還是新hash表呢?
memcache的做法是,判斷舊hash表中,item應(yīng)該插入的桶,是否已經(jīng)遷移至新表中:
(8) 為什么要這么做呢,不能直接插入新hash表嗎?
memcache沒有給出官方的解釋,樓主揣測,這種方法能夠保證一個桶內(nèi)的數(shù)據(jù),只在一個hash表中(要么新表,要么舊表),任何場景下都不會出現(xiàn),舊表新表查詢兩次,以提升查詢速度。
(9) memcache是怎么實(shí)現(xiàn)key過期的,懶淘汰(lazy expiration)具體是怎么玩的?
實(shí)現(xiàn)“超時”和“過期”,最常見的兩種方法是:
這兩種方法,都需要有額外的資源消耗。
mc的查詢業(yè)務(wù)非常簡單,只會返回cache hit與cache miss兩種結(jié)果,這種場景下,非常適合使用懶淘汰的方式。
懶淘汰的核心是:
舉個例子,假如set了一個key,有效期100s:
這種方式的實(shí)現(xiàn)代價很小,消耗資源非常低:
內(nèi)存總是有限的,chunk數(shù)量有限的情況下,能夠存儲的item個數(shù)是有限的,假如chunk被用完了,該怎么辦?
仍然是上面的例子,假如128B的chunk都用完了,用戶又set了一個100B的item,要不要擠掉已有的item?要。
這里的啟示是:
(10) 擠掉哪一個item?怎么擠?
這里涉及LRU淘汰機(jī)制。
如果操作系統(tǒng)的內(nèi)存管理,最常見的淘汰算法是FIFO和LRU:
使用LRU算法擠掉item,需要增加兩個屬性:
并增加一個LRU鏈表,就能夠快速實(shí)現(xiàn)。
畫外音:所以,管理chunk的每個slab,除了free_chunk_list,還有l(wèi)ru_list。
思路比結(jié)論重要。
【本文為專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】
戳這里,看該作者更多好文

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流