1. 程式人生 > >Memcached學習筆記之三:詳解MemCached原理

Memcached學習筆記之三:詳解MemCached原理

memcached是一個高效能的分散式記憶體快取伺服器,memcached在Linux上可以通過yum命令安裝,這樣方便很多,在生產環境下建議用Linux系統,memcached使用libevent這個庫在Linux系統上才能發揮它的高效能。它的分散式其實在服務端是不具有分散式的特徵的,是依靠客戶端的分散式演算法進行了分散式,memcached是一個純記憶體型的資料庫,這樣在讀寫速度上相對來說比較快。

      memcached的記憶體分配是預先分配記憶體,常規的程式使用記憶體無非是兩種,一種是預先分配,一種是動態分配。動態分配從效率的角度來講相對來說要慢點,因為它需要實時的去分配記憶體使用,但是這種方式的好處就是可以節約記憶體使用空間;memcached採用的是預先分配的原則,這種方式是拿空間換時間的方式來提高它的速度,這種方式會造成不能很高效的利用記憶體空間,但是memcached採用了Slab Allocation機制來解決記憶體碎片的問題,Slab Allocation的基本原理就是按照預先規定的大小,將分配的記憶體分割成特定長度的塊,並把尺寸相同的塊分成組(chunk的集合),借用一下網上的圖:

    

memcached會針對客戶端傳送的資料選擇slab並快取到chunk中,這樣就有一個弊端那就是比如要快取的資料大小是50個位元組,如果被分配到如上圖88位元組的chunk中的時候就造成了33個位元組的浪費,雖然在記憶體中不會存在碎片,但是也造成了記憶體的浪費,這也是我上面說的拿空間換時間的原因,不過memcached對於分配到的記憶體不會釋放,而是重複利用。預設情況下如下圖chunk是1.25倍的增加的,當然也可以自己通過-f設定,這種內部的分割演算法可以參看原始碼下的slabs.c檔案。

      

memcached本身內部不會監視記錄是否過期,而是當get時依靠記錄的過期時間檢查是否過期,這也是memcached的一種惰性過期機制。預設情況下memcached內部也維護著一套LRU置換演算法,當設定的記憶體滿的時候,會進行最近很少使用的資料置換出去從而分配空間,所以對於提升memcached命中率的問題主要還是一是根據業務存放的value值來調整好chunk的大小以達到最大效率的利用記憶體;二是擴大記憶體保證所有快取的資料不被置換出去。

      對於memcached的分散式完全就是依靠客戶端的一致雜湊演算法來達到分散式的儲存,因為本身各個memcached的伺服器之間沒辦法通訊,並不存在副本集或者主從的概念,它的分散式演算法主要是先求出每一個memcached的伺服器節點的雜湊值,並將它們分配到2的32次方的圓上,然後根據儲存的key的雜湊值來對映到這個圓上,屬於哪個區間順時針找到的節點就存到這個伺服器節點上,大致借用圖表示如下圖:

      

然而當新增新的memcached節點的時候必然會打亂現有這個圓的結構,這時候是沒辦法完全保證你以前的key依然會存在之前的節點上,但是這種結構卻是能保證在新增快取伺服器的時候把損失降到最小,受結構調整後key不能命中的只有在這個圓上新增的伺服器節點逆時針的第一臺伺服器上,其他的是不受影響的,借用圖如下:

     

memcached和redis一樣內部的儲存都是key/Value的形式,正是這種雜湊表資料結構保證了在記憶體中查詢的時間的複雜度為O(1),整體上memcached的高效能這兩個雜湊結構起了很大的作用,當然還有memcached的多路複用I/O模型也在高併發下起到了很大的作用。另外memcached的內部操作還具有CAS原子操作,這種利用CPU指令集的操作來保證在單個節點下資料的一致性,效率相對來說比加鎖要高很多。

    其實相比來說很多時候如果做快取的話我可能會選redis,不過memcached也有它的優勢,這個要折中考慮,有時間的話在寫redis的介紹,以上是我對memecached的點滴總結,如有什麼問題,可以關注我的微信公眾號反饋給我,希望對各位讀者有一定的幫助!