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的點滴總結,如有什么問題,可以關注我的微信公眾號反饋給我,希望對各位讀者有一定的幫助!