在應用程序運行的過程當中總會有一些常常須要訪問而且變化不頻繁的數據,若是每次獲取這些數據都須要從數據庫或者外部文件系統中去讀取,性能確定會受到影響,因此一般的作法就是將這部分數據緩存起來,只要數據沒有發生變化每次獲取這些數據的時候直接從內存中區獲取性能確定會大大地提升。在.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功能」,以下圖所示:
html
點擊「打開或關閉Windows功能」以後會看到當前系統啓用的功能的狀態,根據當前機器選擇打開Telnet服務器端或者客戶端功能,以下圖所示:
git
通過上面的操做以後就能夠在客服端遠程查看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類型數據。github
在.NET中應用Memcached
有不少.NET版本的Memcached客戶端程序,在這裏周公使用的Enyim Memcached,能夠到https://github.com/enyim/EnyimMemcached/下載最新的版本。
要想在項目中使用Memcached,須要添加對Enyim.Caching.dll的應用。除此以外,咱們可能還須要在config文件中配置Memcached的信息(也能夠在程序代碼中指定,但那樣不靈活),以下就是一個config文件配置的例子:
web
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <configSections>
- <sectionGroup name="enyim.com">
- <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
- </sectionGroup>
- </configSections>
- <enyim.com protocol="Binary">
- <memcached>
- <servers>
- <add address="localhost" port="11121" />
- <!--<add address="localhost" port="11131" />
- <add address="localhost" port="11141" />
- <add address="localhost" port="11151" />-->
- </servers>
- <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
- </memcached>
- </enyim.com>
- </configuration>
若是咱們配置了多個Memcached的實例,能夠想上面的註釋部分那樣在<servers>節點下添加多個Memcached的實例配置。
這裏須要說明的是若是咱們須要向Memcached中添加自定義數據類型時,咱們須要將該數據類型添加上[Serializable]標記。
下面是一個Enyim Memcached的例子:
算法
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Enyim.Caching;
- using Enyim.Caching.Memcached;
-
-
-
-
-
-
- namespace MemcachedMonitor
- {
- [Serializable]
- public class Person
- {
- public int UserId { get; set; }
- public string UserName { get; set; }
- }
- public class MemcachedDemo
- {
- private static MemcachedClient client = new MemcachedClient("enyim.com/memcached");
-
- public void SetDemo()
- {
- Person person = new Person { UserId = 1, UserName = "李剛" };
-
- bool success=client.Store(StoreMode.Add, person.UserName, person);
-
-
- Console.WriteLine("存儲[{0}]的結果:{1}", person.UserName, success);
- }
-
- public void GetDemo()
- {
- Person person = client.Get<Person>("李剛");
- if (person != null)
- {
- Console.WriteLine("取回[{0}]的結果——UserId:{1},UserName:{2}", "李剛", person.UserId, person.UserName);
- }
- else
- {
- Console.WriteLine("取回[{0}]失敗!", "李剛");
- }
- }
-
- public void MultiGetDemo()
- {
- List<string> personNameList = new List<string>();
- for (int i = 0; i < 10; i++)
- {
- personNameList.Add("李剛00" + i);
- }
-
- IDictionary<string, object> resultList = client.Get(personNameList);
- Person person;
- foreach (KeyValuePair<string, object> item in resultList)
- {
- person = item.Value as Person;
- if (person != null)
- {
- Console.WriteLine("取回[{0}]的結果——UserId:{1},UserName:{2}", "李剛", person.UserId, person.UserName);
- }
- else
- {
- Console.WriteLine("取回[{0}]失敗!", "李剛");
- }
- }
- }
- }
- }
說明:若是須要一次從Memcached中取回多個緩存的數據,能夠參考MultiGetDemo()方法,這樣一來只須要一次網絡通信就能夠取回所有數據,減小網絡鏈接時間。此外,在Memcached客戶端可使用Text或者Binary協議,通過周公千萬次測試比較,使用Binary協議性能略高於使用Text協議。在上面的config文件中周公就配置使用了Binary協議。
總結,使用Memcached這樣的分佈式緩存能夠大大提升應用程序的性能,通過周公測試,正確使用Memcached能夠將單臺服務器的併發訪問數從20提升到1000左右,也就是提升了50倍,這是一個至關客觀的提高!限於篇幅,關於Memcached的更深更詳細的用法沒有在本篇介紹,此文算做拋磚引玉,讀者能夠自行參考其它相關資料。數據庫
周公
2011-03-25緩存
本文出自 「周公(周金橋)的專欄」 博客,請務必保留此出處http://zhoufoxcn.blog.51cto.com/792419/528212服務器