Memcache(一)服務端
目錄
- memcache簡介
- memcache工作原理(1)memcache記憶體管理 記憶體結構 記憶體分配方式 記憶體回收方式(2)memcache分散式 分散式實現原理 分散式演算法分析(3)MemCache執行緒管理
- memcache總結
memcache簡介 memcache是目前主流的一個高效能的分散式記憶體物件快取系統,它以key-value形式在記憶體中儲存資料,由於資料快取在記憶體中,所以相比操作DB而言,它不需要解析SQL、磁碟I/O等開銷,效率更高。memcache通常用於在動態Web應用程式中減輕資料庫負載,提升系統性能。也經常作為伺服器之間資料共享的儲存媒介,比如儲存分散式session。理論上來講,memcache儲存資料的量只取決於伺服器記憶體的大小。 作為一個高效能的分散式快取系統,討論單一快取節點並沒有太大的意義。首先隨著系統使用者的增長或業務的擴充套件等,資料量與訪問量會越來越多,單一節點可儲存的資料量不能滿足需求
- 客戶端,提供可用的memcached伺服器列表及路由演算法等。
- 伺服器,儲存及確定何時丟棄舊資料(如果記憶體不足)或重用記憶體,比如LRU。
分散式環境下互動的總體流程大致可以用下圖表示memcache工作原理
(1)memcache記憶體管理記憶體結構
記憶體回收方式 Lazy Expiration 在1.5.0版本之前,memcached內部不會監視記錄是否過期,而是在get時檢視記錄的時間戳,檢查記錄是否過期。這種技術被稱為lazy(惰性)expiration。因此,memcached不會在過期監視上耗費CPU時間,這樣可以減輕伺服器的負載。從官方描述中看,在1.5.0版本之後,memcache提供了自動監控並清理的機制,這類似於Java的垃圾回收機制一樣,雖然從時間成本上來說會消耗一定的CPU時間,但卻能適時的釋放空間,提高記憶體使用率。
LRU演算法 當memcached的記憶體空間不足時(無法從slab class 獲取到新的空間時),memcache採用LRU演算法根據設定的失效時間清理失效的快取資料,或者從最近未被使用的記錄中搜索,並將其空間分配給新的記錄。從快取的實用角度來看,該模型十分理想。需要注意的是,如果禁用LRU(memcache啟動時沒有指定-M)的情況下記憶體不夠會報出Out Of Memory錯誤。 (注:小寫-m表示分配記憶體大小,預設64M。大寫-M表示啟用LRU演算法)
(2)memcache分散式分散式實現原理 分散式實現原理在上文其實已經說過了,目前memcache多個Server之間互不通訊,各自儲存的資料也不同,每個Server只對自己管理資料負責。所以memcache分散式是通過客戶端實現的,採用了單程序、單執行緒、非同步I/O,基於事件(event_based)的服務方式.使用libevent作為事件通知實現。 Client端通過IP地址和埠號指定Server端,將需要快取的資料是以key->value對的形式儲存在Server端。key的值通過hash進行轉換,根據hash值把value傳遞到對應的具體的某個Server上。當需要獲取物件資料時,也根據key進行。首先對key進行hash,通過獲得的值可以確定它被儲存在了哪臺Server上,然後再向該Server發出請求。Client端只需要知道儲存hash(key)的值在哪臺伺服器上就可以保證存取伺服器一致。分散式路由演算法餘數演算法:用鍵的雜湊值%伺服器臺數,根據餘數確定存取伺服器,這種方法計算簡單高效,但在memcached伺服器增加或減少時,幾乎所有的快取都無法命中,這是餘數演算法一個致命問題。這裡我用不同埠代表不同Server進行了一個簡單的測試,開啟了11211 11311 11411三臺Server,對應如下
Java測試程式碼如下
//獲取伺服器配置,並註冊
CacheConfig cfg = new CacheConfig();
cfg.setServerAddress("192.168.80.128:11211,192.168.80.128:11311,192.168.80.128:11411");
TvlCache cache = TvlCacheFactory.getCache(cfg);
//存
cache.add("0", "0"); //48%3=0,對應11211埠伺服器
cache.add("1", "1"); //對應11311
cache.add("2", "2"); //對應11411
//休眠3s,停掉11411
Thread.sleep(3000);
//取
System.out.println(cache.get("2")); //50%2=0,對應到11211埠伺服器,print:null
不停任何節點的情況下,key"2"存取Server一致,對應11411Server。如果在Thread.sleep(3000)期間停掉11411,對應於下
Consistent Hashing雜湊演算法:首先求出memcached伺服器(節點)的雜湊值,並將其配置到0~的圓(continuum)上。然後用同樣的方法求出儲存資料的鍵的雜湊值,並對映到圓上。然後從資料對映到的位置開始順時針查詢,將資料儲存到找到的第一個伺服器上。如果超過仍然找不到伺服器,就會儲存到第一臺memcached伺服器上。 如果需要從上圖的狀態中新增一臺memcached伺服器。採用餘數演算法會由於伺服器數量的變化而對快取命中率產生巨大影響,但Consistent Hashing中,只有在continuum上增加伺服器的地點逆時針方向的第一臺伺服器上的鍵會受到影響。
memcache總結
- 理論上來說memcache中可以儲存的item資料量是沒有限制的,只要記憶體足夠
- memcache單程序在32位機中最大使用記憶體為2G,64位機則沒有限制
- Key最大為250個位元組,超過該長度無法儲存
- 由於記憶體申請是以page為單位,而page大小預設為1M,所以單個item最大資料是1MB,超過1MB的資料不予儲存(如果需要儲存大集合等資料,建議拆分儲存但記憶儲存的關係)
- memcache服務端是不安全的,比如已知某個memcache節點,可以直接telnet過去,並通過flush_all讓已經存在的鍵值對立即失效,所以memcache伺服器最好配置到內網環境,通過防火牆制定可訪問客戶端,,從物理上進行隔離
- 不能夠遍歷memcache中所有的item,因為這個操作的速度相對緩慢且會阻塞其他的操作
- memcache的高效能源自於兩階段雜湊結構:第一階段在客戶端,通過Hash演算法根據Key值算出一個節點;第二階段在服務端,通過一個內部的Hash演算法,查詢真正的item並返回給客戶端。從實現的角度看,MemCache是一個非阻塞的、基於事件的伺服器程式
- memcache設定新增某一個Key值的時候,傳入expiry為0表示這個Key值永久有效,這個Key值也會在30天之後失效。(版本原始碼)