嘗試使用Memcached遇到的狗血問題


乘着有時間,嘗試下利用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。。。自己的問題,大家也注意下。

接下來的問題,比較頭大,看官請看:

image

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

image

因為第一次用,所以遇到了蠻多問題,記錄下,希望對大家有幫助。今天不是教程,僅僅是開發中遇到的各類問題,自己琢磨這解決,在使用第三方的模塊時,請盡量下載其源代碼,對您會有幫助的。對於Memcached我剛用,還了解的不多,目前只是簡單的緩存后讀取,更高層次的話還需要進步學習。

請不要吝嗇您的左鍵,點擊推薦支持一下,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM