使用Memcached提升.NET應用程序的性能(轉)

原創做品,容許轉載,轉載時請務必以超連接形式標明文章   原始出處  、做者信息和本聲明。不然將追究法律責任。 http://zhoufoxcn.blog.51cto.com/792419/528212

在應用程序運行的過程當中總會有一些常常須要訪問而且變化不頻繁的數據,若是每次獲取這些數據都須要從數據庫或者外部文件系統中去讀取,性能確定會受到影響,因此一般的作法就是將這部分數據緩存起來,只要數據沒有發生變化每次獲取這些數據的時候直接從內存中區獲取性能確定會大大地提升。在.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

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <configuration> 
  3.   <configSections> 
  4.     <sectionGroup name="enyim.com"> 
  5.       <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" /> 
  6.     </sectionGroup> 
  7.   </configSections> 
  8.   <enyim.com protocol="Binary"> 
  9.     <memcached> 
  10.       <servers> 
  11.         <add address="localhost" port="11121" /> 
  12.         <!--<add address="localhost" port="11131" /> 
  13.         <add address="localhost" port="11141" /> 
  14.         <add address="localhost" port="11151" />--> 
  15.       </servers> 
  16.       <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" /> 
  17.     </memcached> 
  18.   </enyim.com> 
  19. </configuration> 


若是咱們配置了多個Memcached的實例,能夠想上面的註釋部分那樣在<servers>節點下添加多個Memcached的實例配置。
這裏須要說明的是若是咱們須要向Memcached中添加自定義數據類型時,咱們須要將該數據類型添加上[Serializable]標記。
下面是一個Enyim Memcached的例子:
 算法

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using Enyim.Caching;  
  6. using Enyim.Caching.Memcached;  
  7. /*  
  8.  * 做者:周公(zhoufoxcn)  
  9.  * 日期:2011-03-24  
  10.  * 原文出處:http://blog.csdn.net/zhoufoxcn 或http://zhoufoxcn.blog.51cto.com  
  11.  * 版權說明:本文能夠在保留原文出處的狀況下使用於非商業用途,周公對此不做任何擔保或承諾。  
  12.  * */ 
  13. namespace MemcachedMonitor  
  14. {  
  15. [Serializable]  
  16. public class Person  
  17. {  
  18.     public int UserId { getset; }  
  19.     public string UserName { getset; }  
  20. }  
  21. public class MemcachedDemo  
  22. {  
  23.     private static MemcachedClient client = new MemcachedClient("enyim.com/memcached");  
  24.  
  25.     public void SetDemo()  
  26.     {  
  27.         Person person = new Person { UserId = 1, UserName = "李剛" };  
  28.         //不帶過時時間的存儲,Memcached將根據LRU來決定過時策略  
  29.         bool success=client.Store(StoreMode.Add, person.UserName, person);  
  30.         //帶過時時間的緩存  
  31.         //bool success = client.Store(StoreMode.Add, person.UserName, person, DateTime.Now.AddMinutes(10));  
  32.         Console.WriteLine("存儲[{0}]的結果:{1}", person.UserName, success);  
  33.     }  
  34.  
  35.     public void GetDemo()  
  36.     {  
  37.         Person person = client.Get<Person>("李剛");  
  38.         if (person != null)  
  39.         {  
  40.             Console.WriteLine("取回[{0}]的結果——UserId:{1},UserName:{2}""李剛", person.UserId, person.UserName);  
  41.         }  
  42.         else 
  43.         {  
  44.             Console.WriteLine("取回[{0}]失敗!""李剛");  
  45.         }  
  46.     }  
  47.  
  48.     public void MultiGetDemo()  
  49.     {  
  50.         List<string> personNameList = new List<string>();  
  51.         for (int i = 0; i < 10; i++)  
  52.         {  
  53.             personNameList.Add("李剛00" + i);  
  54.         }  
  55.         //批量獲取,只經過一次網絡通信就取回全部personNameList中的指定的全部數據  
  56.         IDictionary<stringobject> resultList = client.Get(personNameList);  
  57.         Person person;  
  58.         foreach (KeyValuePair<stringobject> item in resultList)  
  59.         {  
  60.             person = item.Value as Person;  
  61.             if (person != null)  
  62.             {  
  63.                 Console.WriteLine("取回[{0}]的結果——UserId:{1},UserName:{2}""李剛", person.UserId, person.UserName);  
  64.             }  
  65.             else 
  66.             {  
  67.                 Console.WriteLine("取回[{0}]失敗!""李剛");  
  68.             }  
  69.         }  
  70.     }  
  71. }  


說明:若是須要一次從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服務器

相關文章
相關標籤/搜索