乘着有時間,嘗試下利用Memcached進行分布式緩存,其中遇到了不少問題及狗血的事情,開篇記錄下,希望對您有幫助。
我之前的項目為:Asp.Net MVC4 + Nhibernate + MSSQL,利用簡單分層,在用緩存時寫了個緩存接口(還好當時寫了),所以在此基礎上,我的改動其實很簡單,實現這個接口,再切換到Memcached就可以了。
搭建Memcached服務器
搭建服務器很簡單,我用虛擬機虛擬了Ubuntu Server,為何使用Server版本呢?搭建起來比較快,而且啟動也快,使用該用的功能就夠了。搭建后,利用apt-get進行安裝
apt-get memcached
安裝后,memcached其實已經自動啟動了,接下來遇到狗血問題了!
一、telnet 無法連接,解決方案:
檢查VirtualBox的網絡連接方式,如果為NAT請改為橋接模式。此時還無法連接!!因為默認的Memcached配置,使用了本機ip:127.0.0.1 ,此時利用VI修改下配置
vi /etc/memcached.conf
文件打開后,修改下,把-l前面加入#號注釋掉,重啟服務器就可以了。您也可以修改其他默認配置,比如-m后的緩存區大小,-p 端口號等,參數命令可以參考我之前的命令文檔
好了,這時候在本機上,cmd-telnet ip 11211 看下是否已連接成功,如果還不行,請留言。
第一步好了,接下來就是程序的改寫了
Memcached Client的使用
在Client選擇上,我用了Enyim.Cache,@dudu推薦滴,不過已經好久沒更新了,我在其github上下載的源碼,在編譯時出現了強名稱的錯誤,最后利用NuGet 搜索Enyim就能找到了。Enyim使用起來很簡單,只要在config中配置好Memcached的地址及端口,就能利用MemcachedClient類進行操作了。配置如下:
<sectionGroup name="enyim.com"> <section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" /> </sectionGroup>
<enyim.com> <memcached protocol="Binary"> <servers> <add address="192.168.10.108" port="11211" /> </servers> <socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:01:10" deadTimeout="00:02:00" /> </memcached> </enyim.com>
之前說過我用了個Cache的接口,我只要是實現一個Memcached就可以了.我的接口如下:
public interface ICacheProvider { void Set(string key, object value); void Set(string key, object value, DateTime expiration); void Remove(string key); bool Contains(string key); int Count { get; } void Flush(); object GetData(string key); Dictionary<string, object> GetDatas(string[] keys); object[] GetDataArray(string[] keys); }
其實很多MemcachedClient都有,Set對應Store(StoreMode,key,value,expriation)
using (var mc = MemcachedClientFactory.GetClient) { mc.Store(StoreMode.Set, key, value, expiration); }
在此建議您在開發環境下,使用ExecuteStore方法進行存儲,這樣遇到問題可以拋出錯誤
using (var mc = MemcachedClientFactory.GetClient) { #if DEBUG var result = mc .ExecuteStore(StoreMode.Set, key, value, expiration); if (!result.Success) { if (result.Exception != null) { throw new Exception(String.Format("Message:{0}, key:{1}", result.Message, key), result.Exception); } else { throw new Exception( String.Format("Message:{0}, Code:{1}, Key:{2}", result.Message, result.StatusCode, key)); } } #else mc.Store(StoreMode.Set, key, value, expiration); #endif }
MemcachedClientFactory.GetClient是一個工廠,方便以后如果有需求可以更改客戶端。這里要注意下,有時候ExecuteStore不成功不會拋出Exception,但有Message,可以自定義個Exception拋出。
實現后原以為一切都如此簡單,可事實並非如此。您現在看到的實現我用了using,每次創建client,每次關閉,之前不是這樣,我使用的是單例模式,狗血的問題發生了。
Failed to read from the socket ‘xxx.xxx.xxx.xxx’
從服務器無法讀取。。。服務器一切正常,代碼跟蹤后,發覺在緩存的時候,有幾條能緩存,有幾條無法緩存,百度,狗狗,都無法找到滿意的答案,隨后就把MemcacheClient(下面簡稱mc)改成了每次打開和關閉(是否會影響性能,不得而知,求dudu賜教)
改了以后,這個問題算解決了,但原理為何還未知,希望有大俠指點。
解決了一個問題又來一個!!
too large
你妹的,原來memcached默認配置下,對單個對象的大小進行了限制,默認情況是1M,查看了自己需要緩存的對象,確實數據量比較大,自己對緩存出的數據沒有進行篩選字段,好吧!為了不破壞之前的程序,我沒有對數據進行修改,而是修改了memcached server上的配置,vi配置文件,添加 –I 5m,重啟,好了,算勉強解決了,把單個緩存對象改成5M了 - -(勿噴)
想想應該可以了吧!又來了個更狗血的:
Message:Invalid arguments, Code:4,
。。。。神馬意思啊???參數錯誤。。。進入Debug,跟蹤到某個緩存的時候,無法進行緩存,查看數據不大啊,那到底神馬問題啊!!!不經意間,看了下key的值。。。。。你妹。。。超長字符,因用了自定義個一個key生成器,把相關參數都一個一個拼接起來的,so。。。。,看了下長度:280,難道memcached的key有長度限制??速速百度,果然,key默認情況下是250長度,但你又無法配置其長度,好在我的key是由一個靜態方法生成的,汗啊!把長度限制了下,超過的截斷,ok了,問題解決!。
在用Memcached時,還遇到了連接池問題,遇到了定位不成功問題,不過這些都是小問題,自己配置了2個server,一個server被我關閉了,so。。。自己的問題,大家也注意下。
接下來的問題,比較頭大,看官請看:
GroupedEnumerable未標記為序列化。。。。可惡啊,之前都是用Where,Order,Select,Group之類的方法並未ToList,這時候有點厭惡微軟了,為嘛不能序列化。。。。List<T>是個可序列化的類型,為什么這些Enumerable無法序列化呢??大神指點。。。
在嘗試了把幾個Enumerable轉換成List后,問題解決了,但程序中好多地方都這樣寫的,想想目前公司不會轉到Memcached,隨后放棄了后面的修改,因為我的目的僅僅是玩一下而已,呵呵。還有個問題要注意:您要緩存的對象必須都要能夠序列化的,一般都是數據庫Model,要在Model類上,加上Serializable特性,否則無法傳輸。在查看了Enyim的源代碼后,發現其實是使用DefaultTranscoder.Serialize方法進行序列化的,如果您不想改變您之前的所有東東,您可以自己寫個ITranscoder的實現,可以通過配置文件切換。
玩過了Memcached后,准備切換回之前的WebCache模式,想想最近看了IOC的書,對於這種小型的IOC來說,用微軟的Unity就可以了,那就再玩下吧!利用Nuget下載Unity。。。。報錯!!!真的,報錯!!!我用的是管理器下載,提示版本不符。。。看了項目介紹后知道了,原來目前的版本支持的是Framework4.5以上!你妹,那好,我下載低版本的吧,進入了Nuget的控制台,輸入Install-Package Unity –Version 2.1.505.0
因為第一次用,所以遇到了蠻多問題,記錄下,希望對大家有幫助。今天不是教程,僅僅是開發中遇到的各類問題,自己琢磨這解決,在使用第三方的模塊時,請盡量下載其源代碼,對您會有幫助的。對於Memcached我剛用,還了解的不多,目前只是簡單的緩存后讀取,更高層次的話還需要進步學習。
請不要吝嗇您的左鍵,點擊推薦支持一下,謝謝!