1. 程式人生 > >使用Memcached提高.NET應用程式的效能

使用Memcached提高.NET應用程式的效能

在應用程式執行的過程中總會有一些經常需要訪問並且變化不頻繁的資料,如果每次獲取這些資料都需要從資料庫或者外部檔案系統中去讀取,效能肯定會受到影響,所以通常的做法就是將這部分資料快取起來,只要資料沒有發生變化每次獲取這些資料的時候直接從記憶體中區獲取效能肯定會大大地提高。在.NET中提供了一個Cache類可以實現這些功能。在ASP.NET中可以通過HttpContext 物件的 Cache 屬性或 Page 物件的 Cache 屬性來獲取這個類的例項。 在大部分情況下我們都可以使用Cache類來提高ASP.NET的效能,但是使用Cache類也有一些不足,比如我們不能指定Cache類所佔用的記憶體的大小,此外在Cache中快取的資料沒有辦法被另一臺機器上的應用程式直接訪問,因此在本文中提出另一種資料快取方案,那就是使用分散式快取。分散式快取的特點是快取的資料不必和應用程式在同一臺機器上,從而大大增強了快取資料的複用性。在本文介紹如何在.NET應用中使用Memcache作為分散式快取。
Memcached介紹

Memcached 是以LiveJournal 旗下Danga Interactive 公司的Brad Fitzpatric 為首開發的一款軟體。在通常的應用中我們都會將資料儲存到資料庫中,每次需要的時候都會從資料庫去查詢這些資料,如果應用程式的使用者很多就會出現大量併發訪問資料庫的情況,這樣就會增加應用程式的響應時間,使用Memcached就可以有效解決這個問題。memcached是高效能的分散式記憶體快取伺服器。一般的使用目的是,通過快取資料庫查詢結果,減少資料庫訪問次數,以提高動態Web應用的速度、提高可擴充套件性。像大名鼎鼎的Facebook網站就使用了Memcached。周公稍後會提供Windows平臺上32位和64位的Memcached程式。
為了提高效能,Memcached中的資料都儲存在Memcached內建的儲存空間中。因為當Memcached重啟會導致其中的資料全部丟失,所以一般的方案是將資料儲存在資料庫中,每次請求資料的時候先檢視在Memcached有沒有快取,如果有就直接從快取中取出資料;如果沒有,就從資料庫中取出資料返回給應用程式並將請求的資料快取到Memcached中,這樣一來下次請求相同的資料就可以直接從Memcached中讀取而不用再去查資料庫了;一旦對資料有更新,同時更新資料庫和Memcached。
Memcached是一個命令列視窗程式,可以在命令列視窗中啟動也可以封裝在系統服務中啟動。在啟動Memcached時需要提供一些必須的引數,指定Memcached執行時監聽的埠和最大使用的記憶體大小等。如果快取的資料大小超過指定記憶體,那麼Memcached就會按照LRU(Least Recently Used)演算法自動“刪除”不使用的快取(標記為失效),新增的快取資料就可以使用這些標記為失效的資料所佔用的記憶體,這樣就不用擔心Memcached超出所指定記憶體的問題。此外,為了提高效能,在快取資料過期後Memcached並不是從實體記憶體中刪除快取的資料,僅僅在取出改資料的時候檢查它是否已經過了有效期。
目前有多種平臺的Memcached版本,比如Linux、FreeBSD、Solaris (memcached 1.2.5以上版本)、Mac OS X及Windows平臺,在Windows平臺上還有32位和64位版本。
Memcached有一套協議,利用這套協議可以對Memcached進行資料存取和檢視Memcached的狀態,很多程式語言都依據這套協議來操作Memcached,比如PHP、Java、C、C++及C#等。
獲取了對應平臺的Memcached版本就可以執行Memcached了。在這裡僅以Windows平臺上的32位Memcached為例。
執行Memcached:
memcached.exe -p 11121 -m 64
上面的命令是執行Memcached,指定它的監聽埠是11121(這是它的預設埠,可以指定為其它大於1024的埠,因為小於1024的埠已經有了預設指定),最大使用記憶體為64m,如果啟用了Windows防火牆,切記要在防火牆上開啟這個埠。
在除錯程式時可以使用下面的命令列來執行:
memcached.exe -p 11121 -m 64 -vv
這樣就會看到如下的結果:
slab class   1: chunk size     88 perslab 11915
slab class   2: chunk size    112 perslab  9362
slab class   3: chunk size    144 perslab  7281
slab class   4: chunk size    184 perslab  5698
slab class   5: chunk size    232 perslab  4519
slab class   6: chunk size    296 perslab  3542
slab class   7: chunk size    376 perslab  2788
slab class   8: chunk size    472 perslab  2221
slab class   9: chunk size    592 perslab  1771
slab class  10: chunk size    744 perslab  1409
slab class  11: chunk size    936 perslab  1120
slab class  12: chunk size   1176 perslab   891
slab class  13: chunk size   1472 perslab   712
slab class  14: chunk size   1840 perslab   569
slab class  15: chunk size   2304 perslab   455
slab class  16: chunk size   2880 perslab   364
slab class  17: chunk size   3600 perslab   291
slab class  18: chunk size   4504 perslab   232
slab class  19: chunk size   5632 perslab   186
slab class  20: chunk size   7040 perslab   148
slab class  21: chunk size   8800 perslab   119
slab class  22: chunk size  11000 perslab    95
slab class  23: chunk size  13752 perslab    76
slab class  24: chunk size  17192 perslab    60
slab class  25: chunk size  21496 perslab    48
slab class  26: chunk size  26872 perslab    39
slab class  27: chunk size  33592 perslab    31
slab class  28: chunk size  41992 perslab    24
slab class  29: chunk size  52496 perslab    19
slab class  30: chunk size  65624 perslab    15
slab class  31: chunk size  82032 perslab    12
slab class  32: chunk size 102544 perslab    10
slab class  33: chunk size 128184 perslab     8
slab class  34: chunk size 160232 perslab     6
slab class  35: chunk size 200296 perslab     5
slab class  36: chunk size 250376 perslab     4
slab class  37: chunk size 312976 perslab     3
slab class  38: chunk size 391224 perslab     2
slab class  39: chunk size 489032 perslab     2
<96 server listening
<112 server listening
<116 send buffer was 8192, now 268435456
<116 server listening (udp)
在客戶端還可以通過telnet來檢視和操作Memcached,前提是伺服器端和客戶端都支援Telnet協議,在Windows7和Windows2008中預設都不支援,需要在控制面板中安裝和啟用。
首先開啟控制面板,然後點選“開啟或關閉Windows功能”,如下圖所示:

點選“開啟或關閉Windows功能”之後會看到當前系統啟用的功能的狀態,根據當前機器選擇開啟Telnet伺服器端或者客戶端功能,如下圖所示:
 
經過上面的操作之後就可以在客服端遠端檢視Memcached的狀態或者操作Memcached了。下面的命令就是連線到Memcached:
telnet localhost 11121
連線之後會出現一個命令列視窗,在這個命令列視窗中輸入"stats"就可以看到當前Memcached的狀態,如下就是剛剛啟動的Memcached的狀態資料:
STAT pid 852
STAT uptime 1399
STAT time 1300979378
STAT version 1.2.5
STAT pointer_size 32
STAT curr_items 0
STAT total_items 0
STAT bytes 0
STAT curr_connections 3
STAT total_connections 5
STAT connection_structures 4
STAT cmd_get 0
STAT cmd_set 0
STAT get_hits 0
STAT get_misses 0
STAT evictions 0
STAT bytes_read 23
STAT bytes_written 415
STAT limit_maxbytes 67108864
STAT threads 1
END
通過這個資料我們就可以瞭解Memcached的狀態了。
這些資料所代表的意義如下:
pid:32u,伺服器程序ID。
uptime:32u, 伺服器執行時間,單位秒。
time :32u, 伺服器當前的UNIX時間。
version :string, 伺服器的版本號。
curr_items :32u, 伺服器當前儲存的內容數量 Current number of items stored by the server
total_items :32u, 伺服器啟動以來儲存過的內容總數。
bytes :64u, 伺服器當前儲存內容所佔用的位元組數。
curr_connections :32u, 連線數量。
total_connections :32u, 伺服器執行以來接受的連線總數。
connection_structures:32u, 伺服器分配的連線結構的數量。
cmd_get :32u, 取回請求總數。
cmd_set :32u, 儲存請求總數。
get_hits :32u, 請求成功的總次數。
get_misses :32u, 請求失敗的總次數。
bytes_read :64u, 伺服器從網路讀取到的總位元組數。
bytes_written :64u, 伺服器向網路傳送的總位元組數。
limit_maxbytes :32u, 伺服器在儲存時被允許使用的位元組總數。
上面的描述中32u和64u表示32位和64位無符號整數,string表示是string型別資料。


在.NET中應用Memcached
有很多.NET版本的Memcached客戶端程式,在這裡周公使用的Enyim Memcached,可以到https://github.com/enyim/EnyimMemcached/下載最新的版本。
要想在專案中使用Memcached,需要新增對Enyim.Caching.dll的應用。除此之外,我們可能還需要在config檔案中配置Memcached的資訊(也可以在程式程式碼中指定,但那樣不靈活),如下就是一個config檔案配置的例子:

如果我們配置了多個Memcached的例項,可以想上面的註釋部分那樣在<servers>節點下新增多個Memcached的例項配置。
這裡需要說明的是如果我們需要向Memcached中新增自定義資料型別時,我們需要將該資料型別新增上[Serializable]標記。
下面是一個Enyim Memcached的例子:

說明:如果需要一次從Memcached中取回多個快取的資料,可以參考MultiGetDemo()方法,這樣一來只需要一次網路通訊就可以取回全部資料,減少網路連線時間。此外,在Memcached客戶端可以使用Text或者Binary協議,經過周公千萬次測試比較,使用Binary協議效能略高於使用Text協議。在上面的config檔案中周公就配置使用了Binary協議。
總結,使用Memcached這樣的分散式快取可以大大提高應用程式的效能,經過周公測試,正確使用Memcached可以將單臺伺服器的併發訪問數從20提高到1000左右,也就是提高了50倍,這是一個相當客觀的提升!限於篇幅,關於Memcached的更深更詳細的用法沒有在本篇介紹,此文算作拋磚引玉,讀者可以自行參考其它相關資料。

周公
2011-03-25