天天看點

MemberCache學習摘要 Memcache 工作原理

轉自:http://www.cnblogs.com/huanghai223/archive/2013/04/24/3040782.html

緣起: 在資料驅動的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似乎還不太穩定。