在.NET應用程式裡使用memcached暫存Linq資料

  • 4539
  • 0

如果你想增加網站的效率,達到分散式暫存的功能,memcached或許就是你要找的。Facebook也是用這一套。

首先取得相關資源。我用的是memcached Win32版本 http://jehiah.cz/projects/memcached-win32/ version 1.2.1
然後要一個memcached用戶端 http://memcachedproviders.codeplex.com/ version 1.2
記得把用戶端的使用手冊也要一份來讀一下,我開始時沒有手冊浪費了很多日時間。

然後我會跟大家分享一些使用心得。

官方的文件只有一點點,新手也不好懂,所以先簡單握要地說明一下memcached是要做甚麼的。

1. Memcached是一個通用的分散式暫存伺服器系統。

    意思是它可以同時運作多個伺服器,編寫程式時可以把它看成一個大的雜湊,可以用任何程式語言存取它。

2. 它並不會儲存物件,你需要把物件序列化才能儲存到暫存裡。

3. 不管發生其麼事它都不會產生例外,這樣才不會影響程式運作。

我會集中講怎樣使用memcached,而不會解釋怎樣去建置,因為建置不困難,大概沒有人會有問題。

接下來就要為你的應用程式建立用戶端,解壓縮你下載回來的檔案,把三個.dll都加到你專案的參考裡。

然後在web.config或app.config裡的<configSections>區塊加入下列設定:

<section name="cacheProvider" type="MemcachedProviders.Cache.CacheProviderSection, MemcachedProviders"
allowDefinition="MachineToApplication" restartOnExternalChanges="true"/>
<sectionGroup name="enyim.com">
<section name="memcached"
type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching"/>
</sectionGroup>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>

 

這個設定會告訴應用程式將會有一個<cacheprovider>組態和一個<log4net>組態。還會有一個<enyim.com>組態,它裡面還會包含一個<memcached>區塊。你可以直接複制貼上這裡的程式碼,應該不會有問題。

然後在<configuration>區塊裡加入下面的詳細設定。

 

<cacheProvider defaultProvider="MemcachedCacheProvider">
<providers>
<add name="MemcachedCacheProvider" type="MemcachedProviders.Cache.MemcachedCacheProvider, MemcachedProviders"
keySuffix="_MySuffix_" defaultExpireTime="2000"/>
</providers>
</cacheProvider>

<enyim.com>
<memcached>
<servers>
<add address="192.168.1.2" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</enyim.com>

<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}]- %message%newline" />
</layout>
</appender>
<root>
<priority value="WARN"/>
<appender-ref ref="ConsoleAppender">
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="WARN"/>
<levelMax value="FATAL"/>
</filter>
</appender-ref>
</root>
</log4net>
你可以設定一些如預設過期時間等。<servers>區塊裡的<address>就是memcached伺服器的位置,11211是預設的連接埠。

暫存字串和序列化的物件應該是你已經會的事情,序列化一般簡單的類別只需要為類別加上[Serializable]標籤。

現在來看看怎樣和LINQ一起使用。

要序列化LINQ的物件,首先打開.dbml的設計介面,把序列化模式設定為單向。

然後你需要使用DataContractSerializer去實行物件的序列化。更多資訊可以看這裡

.NET有提供好幾種序列器。XML, binary, JSON, 等。我的例子會使用JSON,因為它的效率應該比XML好。

下面的程式碼會示範怎樣序列化和儲存到暫存。

 

//建立特定類別的序列器
DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
//使用一個記憶體流做緩衝.因為序列器不會直接輸出字串
 using (MemoryStream ms = new MemoryStream())
 {
 serializeProvider.WriteObject(ms, myClassArrayObject);
 byte[] l_buffer = new byte[ms.Length];
 ms.Position = 0;
//如果序列化結果長度大於int的長度,會跳過,但你可以根據你的需求作任何處理
 if (ms.Length < int.MaxValue)
 {
 ms.Read(l_buffer, 0, (int)ms.Length);
 string l_serialized = Encoding.Unicode.GetString(l_buffer);
//移除可能存在的相同雜湊值暫存
 DistCache.Remove("keyString");
 DistCache.Add("keyString", l_serialized);
 }
 else
 {
 throw new Exception("object data large.");
 }
 }

然後你可以用telnet去檢查你是否成功把序列化後的物件儲存到memcached裡。

Telnet 到你的伺服器,輸入指令'stats',就可以看到目前memcached的狀態。

curr_items 是目前memcached裡暫存物件的數量。

怎樣選擇好的雜湊值,有很多前人的常規可以跟著用。但我不會在這裡多說明。

我用的方法是 Application:Method:Parameters:Salt 然後用SHA256去產生值,再轉成base64格式。

作為範例這樣的方法應該夠用,你可以設計你自己的雜湊值產生法。

接下來就是取得並反序列化你的暫存。

string l_serialized = (string)DistCache.Get("keyString");
 DataContractJsonSerializer serializeProvider = new DataContractJsonSerializer(typeof(myClass[]));
 using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(l_serialized)))
 {
 myClass[] members = (myClass[])serializeProvider.ReadObject(ms);
 }

你可以用這方法序列化並暫存你的物件、物件陣列、物件集合等。

但要記得你從暫存取出來的物件是在不同的LINQ資料背景(DataContext)。

如果你要更新或刪除這些資料,要再做一些處理。

 有時間我會在別的文章再探討這個問題。

英文版

My WP Blog with english technical docs.