MemberCache學習摘要


緣起: 在數據驅動的web開發中,經常要重復從數據庫中取出相同的數據,這種重復極大的增加了數據庫負載。緩存是解決這個問題的好辦法。
Memcached是什么?
Memcached是由Danga Interactive開發的,高性能的,分布式的內存對象緩存系統,用於在動態應用中減少數據庫負載,提升訪問速度。

 

Memcache 是什么

 

Memcache 是 danga.com 的一個項目,最早是為 LiveJournal 服務的,目前全世界不少人使用這個緩存項目來構建自己大負載的網站,來分擔數據庫的壓力。

它可以應對任意多個連接,使用非阻塞的網絡 IO 。由於它的工作機制是在內存中開辟一塊空間,然后建立一個 HashTable , Memcached 自管理這些 HashTable 。

       Memcache是高性能的分布式內存緩存服務器。一般的使用目的是,通過緩存數據庫查詢結果,減少數據庫訪問次數,以提高動態Web應用的速度、提高可擴展性。

 

 

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

其實 Memcache 是這個項目的名稱,而 memcached 是它服務器端的主程序文件名,

 

Memcache 官方網站: http://www.danga.com/memcached

 

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 表,來存儲經常被讀寫的一些數組與文件,從而極大的提高網站的運行效率。

 

 

memcached的特征

memcached作為高速運行的分布式緩存服務器,具有以下的特點。

  • 協議簡單
  • 基於libevent的事件處理
  • 內置內存存儲方式
  • memcached不互相通信的分布式

協議簡單

memcached的服務器客戶端通信並不使用復雜的XML等格式,而使用簡單的基於文本行的協議。因此,通過telnet 也能在memcached上保存數據、取得數據。下面是例子。

$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
set foo 0 0 3     (保存命令)
bar               (數據)
STORED            (結果)
get foo           (取得命令)
VALUE foo 0 3     (數據)
bar               (數據)

協議文檔位於memcached的源代碼內,也可以參考以下的URL。

  • http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt

基於libevent的事件處理

libevent是個程序庫,它將Linux的epoll、BSD類操作系統的kqueue等事件處理功能封裝成統一的接口。即使對服務器的連接數增加,也能發揮O(1)的性能。 memcached使用這個libevent庫,因此能在Linux、BSD、Solaris等操作系統上發揮其高性能。關於事件處理這里就不再詳細介紹,可以參考Dan Kegel的The C10K Problem。

  • libevent : http://www.monkey.org/~provos/libevent/
  • The C10K Problem : http://www.kegel.com/c10k.html

內置內存存儲方式

為了提高性能,memcached中保存的數據都存儲在memcached內置的內存存儲空間中。由於數據僅存在於內存中,因此重啟memcached、重啟操作系統會導致全部數據消失。另外,內容容量達到指定值之后,就基於LRU(Least Recently Used)算法自動刪除不使用的緩存。 memcached本身是為緩存而設計的服務器,因此並沒有過多考慮數據的永久性問題。關於內存存儲的詳細信息,本連載的第二講以后前坂會進行介紹,請屆時參考。

memcached不互相通信的分布式

memcached盡管是“分布式”緩存服務器,但服務器端並沒有分布式功能。各個memcached不會互相通信以共享信息。那么,怎樣進行分布式呢?這完全取決於客戶端的實現。本連載也將介紹memcached的分布式。

 


Memcached能緩存什么?
       通過在內存里維護一個統一的巨大的hash表,Memcached能夠用來存儲各種格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。

Memcached快么?
       非常快。Memcached使用了libevent(如果可以的話,在linux下使用epoll)來均衡任何數量的打開鏈接,使用非阻塞的網絡I/O,對內部對象實現引用計數(因此,針對多樣的客戶端,對象可以處在多樣的狀態), 使用自己的頁塊分配器和哈希表, 因此虛擬內存不會產生碎片並且虛擬內存分配的時間復雜度可以保證為O(1).。
       Danga Interactive為提升Danga Interactive的速度研發了Memcached。目前,LiveJournal.com每天已經在向一百萬用戶提供多達兩千萬次的頁面訪問。而這些,是由一個由web服務器和數據庫服務器組成的集群完成的。Memcached幾乎完全放棄了任何數據都從數據庫讀取的方式,同時,它還縮短了用戶查看頁面的速度、更好的資源分配方式,以及Memcache失效時對數據庫的訪問速度。

Memcached的特點
       Memcached的緩存是一種分布式的,可以讓不同主機上的多個用戶同時訪問, 因此解決了共享內存只能單機應用的局限,更不會出現使用數據庫做類似事情的時候,磁盤開銷和阻塞的發生。

 

 


Memcached的使用
一 、Memcached服務器端的安裝 (此處將其作為系統服務安裝)
     下載文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
   1 解壓縮文件到c:\memcached
   2 命令行輸入 'c:\memcached\memcached.exe -d install'
   3 命令行輸入 'c:\memcached\memcached.exe -d start' ,該命令啟動 Memcached ,默認監聽端口為 11211
  通過 memcached.exe -h 可以查看其幫助

 

ps:安裝時報錯誤的話,如果是WIN7系統,那么用管理員身份進入CMD模式,找到CMD.EXE,用右鍵選擇管理員模式進入就可以了。

 

memcached.exe -p 11211 -m 64m -vv    




-p 使用的TCP端口。默認為11211
-m 最大內存大小。默認為64M
-vv 用very vrebose模式啟動,調試信息和錯誤輸出到控制台
-d

作為daemon在后台啟動

 

-d restart 重啟memcached服務

-d stop|shutdown 關閉正在運行的memcached服務

-M 內存耗盡時返回錯誤,而不是刪除項

-c 最大同事連接數,默認是1024

-f 塊大小增長因子,默認是1.25

-n 最小分配空間 key+value+flags默認是48

-h 顯示幫助


二、客戶端使用
      下載memcached java client:http://www.whalin.com/memcached/#download
   1 解壓后將java_memcached-release_2.0.1.jar jar包添加到工程的classpath中
       2 利用memcached java client 一個簡單的應用

 

 

public class TestMemberCache {

	// 創建全局的唯一實例
	protected static MemCachedClient mcc = new MemCachedClient();

	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的規則就是在發送一個包之前,本地機器會等待遠程主機
		// 對上一次發送的包的確認信息到來;這個方法就可以關閉套接字的緩存,
		// 以至這個包准備好了就發;

		// 設置TCP的參數,連接超時等
		pool.setNagle(false);
		pool.setSocketTO(3000);
		pool.setSocketConnectTO(0);

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

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

	public static void bulidCache() {
		// set(key,value,Date) ,Date是一個過期時間,如果想讓這個過期時間生效的話,這里傳遞的new Date(long
		// date) 中參數date,需要是個大於或等於1000的值。
		// 因為java client的實現源碼里是這樣實現的 expiry.getTime() / 1000 ,也就是說,如果
		// 小於1000的值,除以1000以后都是0,即永不過期
		mcc.set("test", "This is a test String", new Date(10000));
		mcc.set("test", "This is a test String111", new Date(10000));// 十秒后過期

		User u = new User();
		u.setUsername("aaaa");
		mcc.set("user", u);
		User u1 = (User) mcc.get("user");
		System.out.println(u1.getUsername());

		
		// add 當這個 key 不存在的時候才保存 value
		// replace 當 key 相同的時候才替換 value
		// set 直接寫入新的 value ,如果 key 存在就是替換 value

	}

	public static void output() {
		// 從cache里取值
		String value = (String) mcc.get("test");
		System.out.println(value);
	}

	public static void main(String[] args) {

		bulidCache();
		output();
	}

}

 

     輸出結果為:

     aaaa
     This is a test String111

 

 

    MemberCache及其他緩存等相關知識:

 

1)JBOSS CACHE, EHCACHE, 等JAVA寫成的CACHE,一般都是和主程序在同一機器上,內存直接訪問,比memcached要快。但如果有多個server,每個server都有自己的一份cache,要采用一些notification or replicate機制才能synchronize。而且,cache size受制於heap size setting。memcached 運行在主程序以外的機器上,通過網絡訪問來傳遞數據。因為是專門的server,所以size不受限制。如果cache data 不大(300MB以下?),無須用memcached.

 

2)memcached組成它的n台機器里有一個down了,並不會整個掛掉,只會訪問某些cache內容無法命中,就算全部掛掉,Cache就是減少對數據庫訪問的,所以無非就是對數據庫壓力大一些而已,如果希望Cache持久化,或者帶有故障切換功能,可以用memcachedb。

 

3)Cache Server的可靠性比DB Server還要高

 

4)memcached 要求set的對象必須是可序列化對象,jboss cache等java obect cache是沒有這個說法的,這是本質的不同的,但是他可以在網絡上用,所以必須序列化也可理解

 

5)memcached 並發連接可以上到1w,我手頭的應用常常保持在3-5k;它的快不僅是因為用了libevent,還因為它采取了“用內存冗余換存取速度”的內存管理策略,網上有文章專門分析它的內存分配回收管理的源碼,講的很清楚,在這上面jboss cache、ehcache、oscache跟它沒法比;memcached的集群也非常好,聽說國外有200+的memcached集群,我們也有這方面的嘗試,效果也很好,一台down掉根本不會引起其他機器down掉,只是這台的數據丟了,需要慢慢積累回來;而且支持多客戶端,java、php、 python、ruby可以共享數據,就把它當作數據庫用。
我的建議是:你的應用訪問量比較大,對響應速度要求很高,對數據一致性要求一般時,用它,擋在數據庫前面,非常爽(memcached是互聯網公司開發的,正好滿足這三個條件);如果應用不忙,用用ehcache就行了。

 

6)ehcache、oscache 的數據都是在本機服務器上的,訪問時走的僅是系統總線。而memcached走的是網絡。關於傳輸速度來講我們的應用讀取memcached的網絡流量是每秒有2MB的流量,是讀取數據庫的網絡流量的大約5倍。但是你要知道現在隨便的PC機都是千兆網卡,因此 memcached的get/set操作的延時非常少,並不比echache的get/set慢多少。在一個完整的web應用當中,我的壓力測試表明,性能差異 <= 5%

 

7)論壇、sns這樣的應用,會使用多種技術進行緩存。
     拿sohu的bbs來說吧,pv為5000w,峰值8000w
     其中帖子、評論讀寫頻繁,其他部分讀頻繁。  
     帖子列表、評論列表使用c開發(其中排序算法很巧妙),socket調用
     帖子、評論內容使用squid緩存

     其他讀頻繁的部分使用memcached、squid、定時生成靜態頁面等多種技術。
     數據庫用mysql,分表。
     個人認為,小規模應用中,jvm級別的cache可以用用,memcached可用可不用
     大規模網站應用,肯定是系統水平切分,多種cache結合。

 

8)memcached非常快,但我沒說過比本機的ehcache還快,但用本地緩存有兩點不爽:
1.緩存放在內存or放在磁盤?應用重啟會導致內存緩存丟失,放在磁盤又不夠快。內存開多大合適?如果是大訪問量應用,緩存對象集中淘汰可能引起服務器load急劇波動(我們吃過虧,現在也開ehcache,但緩存對象的上限開的很小)
2.集群應用里緩存對象如何共享?jboss cache用的是廣播,訪問量大的時候,可以把你的服務拖死,這個我們也吃過虧
當然,有人談到了sohu的例子,一旦訪問量大了,各種緩存都得用着,目前我們就是squid + memcached + ehcache。squid也是好東西,但緩存內容刪除不太靈活,比較適合web1.0,比如新浪搜狐的新聞
另外,java memcached client用1.6好了,沒必要升級到2.1,2.X似乎還不太穩定。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM