memcache是互聯網分層架構中,使用最多的的KV緩存。面試的過程當中,memcache相關的問題幾乎是必問的,關於memcache的面試提問,你能回答到哪個層次呢?
畫外音:極可能關乎,你拿到offer的薪酬檔位。面試
這一類問題,考察用沒用過,知不知道,相對比較好回答。redis
關於memcache一些基礎特性,使用過的小夥伴基本都能回答出來:
(1)mc的核心職能是KV內存管理,value存儲最大爲1M,它不支持複雜數據結構(哈希、列表、集合、有序集合等);
(2)mc不支持持久化;
(3)mc支持key過時;
(4)mc持續運行不多會出現內存碎片,速度不會隨着服務運行時間下降;
(5)mc使用非阻塞IO複用網絡模型,使用監聽線程/工做線程的多線程模型;算法
面對這類封閉性的問題,必定要斬釘截鐵,毫無猶豫的給出回答。緩存
這一類問題,考察對於一個工具,只停留在使用層面,仍是有原理性的思考。網絡
業務決定技術方案,mc的誕生,以「以服務的方式,而不是庫的方式管理KV內存」爲設計目標,它顛覆的是,KV內存管理組件庫,複雜數據結構與持久化並非它的初衷。數據結構
固然,用「顛覆」這個詞未必不合適,庫和服務各有使用場景,只是在分佈式的環境下,服務的使用範圍更廣。設計目標,誕生背景很重要,這必定程度上決定了實現方案,就如redis的出現,是爲了有一個更好用,更多功能的緩存服務。
畫外音:我很喜歡問這個問題,大部分候選人面對這個沒有標準答案的問題,狀態多是蒙圈。多線程
懶淘汰(lazy expiration)。架構
提早分配內存。分佈式
目的是提升吞吐量。
多線程可以充分的利用多核,但會帶來一些鎖衝突。ide
面對這類半開放的問題,有些並無標準答案,必定要回答出本身的思考和看法。
這一類問題,探測候選人理解得有多透,掌握得有多細,對技術有多刨根究底。
畫外音:所謂「好奇心」,真的很重要,只想要「一份工做」的技術人很難有這種好奇心。
開講以前,先解釋幾個很是重要的概念:
chunk:它是將內存分配給用戶使用的最小單元。
item:用戶要存儲的數據,包含key和value,最終都存儲在chunk裏。
slab:它會管理一個固定chunk size的若干個chunk,而mc的內存管理,由若干個slab組成。
畫外音:爲了不復雜性,本文先不引入page的概念了。
如上圖所示,一系列slab,分別管理128B,256B,512B…的chunk內存單元。
將上圖中管理128B的slab0放大:
可以發現slab中的一些核心數據結構是:
會從最接近item大小的slab的chunk[]中,經過free_chunk_list快速找到對應的chunk,如上圖所示,與item大小最接近的chunk是128B。
### 爲何不會出現內存碎片呢?
拿到一個128B的chunk,去存儲一個100B的item,餘下的28B不會再被其餘的item所使用,即:實際上浪費了存儲空間,來減小內存碎片,保證訪問的速度。
畫外音:理論上,內存碎片幾乎不存在。
memcache經過slab,chunk,free_chunk_list來快速分配內存,存儲用戶的item,那它又是如何快速實現key的查找的呢?
沒有什麼特別算法:
用最樸素的方式,實現key的快速查找。
當item總數達到hash表長度的1.5倍時,hash表會動態擴容,rehash將數據從新分佈,以保證查找效率不會不斷下降。
擴展hash表以後,同一個key在新舊hash表內的位置會發生變化,如何保證數據的一致性,以及如何保證遷移過程服務的可用性呢(確定不能加一把大鎖,遷移完成數據,再從新服務吧)?
哈希表擴展,數據遷移是一個耗時的操做,會有一個專門的線程來實施,爲了不大鎖,採用的是「分段遷移」的策略。
當item數量達到閾值時,遷移線程會分段遷移,對hash表中的一部分桶進行加鎖,遷移數據,解鎖:
新的問題來了,對於已經存在與舊hash表中的item,能夠經過上述方式遷移,那麼在item遷移的過程當中,若是有新的item插入,是應該插入舊hash表仍是新hash表呢?
memcache的作法是,判斷舊hash表中,item應該插入的桶,是否已經遷移至新表中:
爲何要這麼作呢,不能直接插入新hash表嗎?
memcache沒有給出官方的解釋,樓主揣測,這種方法可以保證一個桶內的數據,只在一個hash表中(要麼新表,要麼舊錶),任何場景下都不會出現,舊錶新表查詢兩次,以提高查詢速度。
實現「超時」和「過時」,最多見的兩種方法是:
mc的查詢業務很是簡單,只會返回cache hit與cache miss兩種結果,這種場景下,很是適合使用懶淘汰的方式。
懶淘汰的核心是:
舉個例子,假如set了一個key,有效期100s:
這種方式的實現代價很小,消耗資源很是低:
內存老是有限的,chunk數量有限的狀況下,可以存儲的item個數是有限的,假如chunk被用完了,該怎麼辦?
仍然是上面的例子,假如128B的chunk都用完了,用戶又set了一個100B的item,要不要擠掉已有的item?
要。
這裏的啓示是:
(1)即便item的有效期設置爲「永久」,也可能被淘汰;
(2)若是要作全量數據緩存,必定要仔細評估,cache的內存大小,必須大於,全量數據的總大小,不然很容易採坑;
這裏涉及LRU淘汰機制。
若是操做系統的內存管理,最多見的淘汰算法是FIFO和LRU:
使用LRU算法擠掉item,須要增長兩個屬性:
思路比結論重要。
架構師之路-分享技術思路
文章較長,如有收穫,幫忙轉發+再看一下。
調研:面試memcache內核,你在哪一個檔位?