1. 程式人生 > >Memcache工作原理及其例子

Memcache工作原理及其例子

1       Memcache是什麼

Memcache是danga.com的一個專案,最早是為 LiveJournal 服務的,目前全世界不少人使用這個快取專案來構建自己大負載的網站,來分擔資料庫的壓力。

它可以應對任意多個連線,使用非阻塞的網路IO。由於它的工作機制是在記憶體中開闢一塊空間,然後建立一個HashTable,Memcached自管理這些HashTable。

為什麼會有Memcache和memcached兩種名稱?

其實Memcache是這個專案的名稱,而memcached是它伺服器端的主程式檔名,

2       Memcache工作原理

首先 memcached 是以守護程式方式運行於一個或多個伺服器中,隨時接受客戶端的連線操作,客戶端可以由各種語言編寫,目前已知的客戶端 API 包括 Perl/PHP/Python/Ruby/Java/C#/C 等等。客戶端在與 memcached 服務建立連線之後,接下來的事情就是存取物件了,每個被存取的物件都有一個唯一的識別符號 key,存取操作均通過這個 key 進行,儲存到memcached 中的物件實際上是放置記憶體中的,並不是儲存在 cache 檔案中的,這也是為什麼 memcached 能夠如此高效快速的原因。注意,這些物件並不是持久的,服務停止之後,裡邊的資料就會丟失。

與許多 cache 工具類似,Memcached 的原理並不複雜。它採用了C/S的模式,在 server 端啟動服務程序,在啟動時可以指定監聽的 ip,自己的埠號,所使用的記憶體大小等幾個關鍵引數。一旦啟動,服務就一直處於可用狀態。Memcached 的目前版本是通過C實現,採用了單程序,單執行緒,非同步I/O,基於事件 (event_based) 的服務方式.使用libevent 作為事件通知實現。多個 Server 可以協同工作,但這些 Server 之間是沒有任何通訊聯絡的,每個 Server 只是對自己的資料進行管理。Client 端通過指定 Server 端的 ip 地址(通過域名應該也可以)。需要快取的物件或資料是以 key->value對的形式儲存在Server端。key 的值通過 hash 進行轉換,根據 hash 值把 value 傳遞到對應的具體的某個 Server 上。當需要獲取物件資料時,也根據 key 進行。首先對 key 進行 hash,通過獲得的值可以確定它被儲存在了哪臺 Server 上,然後再向該 Server 發出請求。Client 端只需要知道儲存 hash(key) 的值在哪臺伺服器上就可以了。

        其實說到底,memcache 的工作就是在專門的機器的記憶體裡維護一張巨大的 hash 表,來儲存經常被讀寫的一些陣列與檔案,從而極大的提高網站的執行效率。

3       如何使用

  • 建立Manager類

package com.alisoft.sme.memcached;

import java.util.Date;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

public class MemCachedManager {

	// 建立全域性的唯一例項
	protected static MemCachedClient mcc = new MemCachedClient();

	protected static MemCachedManager memCachedManager = new MemCachedManager();

	// 設定與快取伺服器的連線池
	static {
		// 伺服器列表和其權重
		String[] servers = { "127.0.0.1:11211" };
		Integer[] weights = { 3 };

		// 獲取socke連線池的例項物件
		SockIOPool pool = SockIOPool.getInstance();

		// 設定伺服器資訊
		pool.setServers(servers);
		pool.setWeights(weights);

		// 設定初始連線數、最小和最大連線數以及最大處理時間
		pool.setInitConn(5);
		pool.setMinConn(5);
		pool.setMaxConn(250);
		pool.setMaxIdle(1000 * 60 * 60 * 6);

		// 設定主執行緒的睡眠時間
		pool.setMaintSleep(30);

		// 設定TCP的引數,連線超時等
		pool.setNagle(false);
		pool.setSocketTO(3000);
		pool.setSocketConnectTO(0);

		// 初始化連線池
		pool.initialize();

		// 壓縮設定,超過指定大小(單位為K)的資料都會被壓縮
		mcc.setCompressEnable(true);
		mcc.setCompressThreshold(64 * 1024);
	}

	/**
	 * 保護型構造方法,不允許例項化!
	 * 
	 */
	protected MemCachedManager() {

	}

	/**
	 * 獲取唯一例項.
	 * 
	 * @return
	 */
	public static MemCachedManager getInstance() {
		return memCachedManager;
	}

	/**
	 * 新增一個指定的值到快取中.
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	public boolean add(String key, Object value) {
		return mcc.add(key, value);
	}

	public boolean add(String key, Object value, Date expiry) {
		return mcc.add(key, value, expiry);
	}

	public boolean replace(String key, Object value) {
		return mcc.replace(key, value);
	}

	public boolean replace(String key, Object value, Date expiry) {
		return mcc.replace(key, value, expiry);
	}

	/**
	 * 根據指定的關鍵字獲取物件.
	 * 
	 * @param key
	 * @return
	 */
	public Object get(String key) {
		return mcc.get(key);
	}

	public static void main(String[] args) {
		MemCachedManager cache = MemCachedManager.getInstance();
		cache.add("hello", 234);
		System.out.print("get value : " + cache.get("hello"));
	}
}

建立資料物件

建立資料物件

package com.alisoft.sme.memcached;

import java.io.Serializable;

public class TBean implements Serializable {
	
	private static final long serialVersionUID = 1945562032261336919L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


建立測試用例

package com.alisoft.sme.memcached.test;

import junit.framework.TestCase;

import org.junit.Test;

import com.alisoft.sme.memcached.MemCachedManager;
import com.alisoft.sme.memcached.TBean;

public class TestMemcached extends TestCase {

	private static MemCachedManager cache;

	@Test
	public void testCache() {
		
		TBean tb = new TBean();
		tb.setName("E網打進");
		cache.add("bean", tb);
		
		TBean tb1 = (TBean) cache.get("bean");
		System.out.println("name=" + tb1.getName());
		tb1.setName("E網打進_修改的");
		
		tb1 = (TBean) cache.get("bean");
		System.out.println("name=" + tb1.getName());
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		cache = MemCachedManager.getInstance();
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		cache = null;
	}

}


測試結果

[INFO] ++++ serializing for key: bean for class: com.alisoft.sme.memcached.TBean
[INFO] ++++ memcache cmd (result code): add bean 8 0 93 (NOT_STORED)
[INFO] ++++ data not stored in cache for key: bean
[INFO] ++++ deserializing class com.alisoft.sme.memcached.TBean
name=E網打進
[INFO] ++++ deserializing class com.alisoft.sme.memcached.TBean
name=E網打進