網站架構之緩存應用

作者: 姜敏  來源: 博客園  發布時間: 2011-01-27 10:46  閱讀: 2139 次  推薦: 2   原文鏈接   [收藏]  

      這篇來講如何利用memcached實現一級緩存,以及如何讓一級緩存組件支持在企業庫,memcached或者其它第三方實施方案之間的切換。memcached本人并沒有太多經驗,如果文中有說的不對的地方,還希望批評指出,且文中關于memcached的代碼大多來自網絡。
     創建memcached實現類MemcachedWebCacheProvider,由它來繼承緩存提供者接口IWebCacheProvider,主里memcached客戶端我采用.NET memcached client library ,這個類庫很久沒有更新這過了,沒有和java版同步,有部分功能目前沒有實現。
     1:初始化memcached服務,這段初始化代碼在程序中保證執行一次就夠,一般可以放在gloabl文件中,或者是設置一個靜態變量來存儲服務的狀態。

 private void Setup()
        {
            String[] serverlist 
= { "127.0.0.1:11211" };
            
this._pool = SockIOPool.GetInstance("default");
            
this._pool.SetServers(serverlist); //設置服務器列
            
//各服務器之間負載均衡的設置
            this._pool.SetWeights(new int[] { 1 });
            
//socket pool設置
            this._pool.InitConnections = 5//初始化時創建的連接數
            this._pool.MinConnections = 5//最小連接數
            this._pool.MaxConnections = 250//最大連接數
            
//連接的最大空閑時間,下面設置為6個小時(單位ms),超過這個設置時間,連接會被釋放掉
            this._pool.MaxIdle = 1000 * 60 * 60 * 6;
            
//通訊的超時時間,下面設置為3秒(單位ms),.NET版本沒有實現
            this._pool.SocketTimeout = 1000 * 3;
            
//socket連接的超時時間,下面設置表示連接不超時,即一直保持連接狀態
            this._pool.SocketConnectTimeout = 0;
            
this._pool.Nagle = false//是否對TCP/IP通訊使用Nalgle算法,.NET版本沒有實現
            
//維護線程的間隔激活時間,下面設置為60秒(單位s),設置為0表示不啟用維護線程
            this._pool.MaintenanceSleep = 60;
            
//socket單次任務的最大時間,超過這個時間socket會被強行中斷掉(當前任務失敗)
            this._pool.MaxBusy = 1000 * 10;
            
this._pool.Initialize();
        }

        2:獲取一個memcached客戶端。     

        private MemcachedClient GetClient()
        {
            MemcachedClient client 
= new MemcachedClient();
            client.PoolName 
= "default";
            
return client;
        }

        3:根據memcached提供的功能實現IWebCacheProvider,代碼就不貼了,大家可以自己去試試。
        到此我們就利用memcached實現了一級緩存,由于.NET memcached client library 實現了分布式,我們只需要在多臺服務器上安裝上memcached服務,在初始化memcached代碼中增加了服務器相關配置即可。String[] serverlist = { "127.0.0.1:11211" }; 
        如何讓一級緩存組件支持多實現方案之間的切換。
        MyWebCacheServiceClient:客戶端緩存組件實例,它來完成一級緩存與二級緩存之間的聯系,以及根據配置文件來選擇一級緩存的實施方案。
        第一:CacheServiceMode,根據它就可以決定緩存是只緩存二級緩存還是兩級都緩存。

                 1:LocalCacheOnlyMode,只啟用web server上的二級緩存。

                 2:BufferedLCacheServerMode,即啟用web server上的二級緩存也啟用cache server上的緩存。

                 3:Off,關閉緩存功能。
        第二:IWebCacheProvider service = this .GetPrimaryCacheProvider(hashKey);方式決定了一級緩存的實施方案。

代碼
/// <summary>
        /// 獲取一級緩存
        
/// </summary>
        /// <param name="hashKey"></param>
        /// <param name="configFilePath"></param>
        /// <returns></returns>
        private IWebCacheProvider GetPrimaryCacheProvider(uint hashKey)
        {
            IWebCacheProvider provider 
= null;
            
string cacheType = WebConfig.ChannelConfig["CacheType"].ToString().ToLower();
            
switch (cacheType)
            {
                
case "memcached":
                    provider 
= WebCacheProviderFactory.GetMemcachedWebCacheProvider(configFilePath);
                    
break;
                
case "entlib":
                    provider 
= servicePool.GetServiceClient(hashKey) as IWebCacheProvider;
                    
break;
            }
           
            
return provider;
        }

         插入緩存的邏輯:原理就是根據配置文件中的CacheMode來完成緩存級別的判定以及一級緩存的方案。

代碼
public void Insert(string key, object value, string region, string subRegion, CacheItemConfig cacheItemConfig)
        {
            
if (string.IsNullOrEmpty(key) || value == null)
                
return;
            
//關閉模式,不使用緩存
            if (Options.CacheServiceMode == ECacheServiceMode.Off)
            {
                
return;
            }
            
else if (Options.CacheServiceMode == ECacheServiceMode.BufferedLCacheServerMode
                
|| Options.CacheServiceMode == ECacheServiceMode.LocalAndCacheServerAndSql
                
|| Options.CacheServiceMode == ECacheServiceMode.LocalCacheOnlyMode)
            {
//使用帶緩沖的模式
                if (Options.BufferType == ECacheDependencyType.SlidingTime)
                {
                    SecondaryCacheProvider.Insert(key, value, region, subRegion, MyCacheItemPriority.Normal, Options.BufferSlidingTime);
                }
                
else if (Options.BufferType == ECacheDependencyType.AbsoluteTime)
                {
                    SecondaryCacheProvider.Insert(key, value, region, subRegion, MyCacheItemPriority.Normal, Options.BufferAbsoluteTime);
                }

                
if (Options.CacheServiceMode == ECacheServiceMode.LocalCacheOnlyMode)
                {
//只使用本地緩存
                    return;
                }
            }

            checkKey(key);
            
uint hashKey = hash(key);

            
try
            {
                
if (Options.CacheServiceMode == ECacheServiceMode.CacheServerMode
                    
|| Options.CacheServiceMode == ECacheServiceMode.BufferedLCacheServerMode
                    
|| Options.CacheServiceMode == ECacheServiceMode.CacheServerAndSql
                    
|| Options.CacheServiceMode == ECacheServiceMode.LocalAndCacheServerAndSql)
                {
//CacheServer模式使用Cache服務器保存Cache                                      
                    IWebCacheProvider service = this .GetPrimaryCacheProvider(hashKey);
                    
byte[] byteValue = SerializationHelper.SaveToBinaryBytes(value);
                    var cachePriority 
= ModelConverter.ToRefClass(cacheItemConfig.CachePriority);
                    
if (cacheItemConfig.CacheType == ECacheDependencyType.AbsoluteTime)
                    {
                        AbsoluteTimeCacheDependency absTime 
= new AbsoluteTimeCacheDependency();
                        absTime.AbsoluteTime 
= DateTime.Now.AddMinutes(cacheItemConfig.CacheTimeMinutes);
                        service.Insert(key, byteValue, region, subRegion, cachePriority, absTime);
                    }
                    
else if (cacheItemConfig.CacheType == ECacheDependencyType.SlidingTime)
                    {
                        SlidingTimeCacheDependency slTime 
= new SlidingTimeCacheDependency();
                        slTime.SlidingTime 
= new TimeSpan(0, cacheItemConfig.CacheTimeMinutes, 0);
                        service.Insert(key, byteValue, region, subRegion, cachePriority, slTime);
                    }
                }
            }
            
catch (Exception ex)
            {
//出現異常,保存到數據庫中
                servicePool.ReplaceServiceClient(hashKey);
                
this.SendLogEmail(ex);
            }
           

        }

 

        客戶端調用代碼:為了調用方便,創建一個CacheHelper來幫助完成:

代碼
public class CacheHelper
    {
        
/// <summary>
        /// 主分區
        
/// </summary>
        public const string REGION = "MyBlog";
        
/// <summary>
        /// 子分區
        
/// </summary>
        public const string SUB_REGION = "default";
        
public const string BlogListConfigKey = "BlogListConfigKey";
        
#region 頁面間數據傳遞
        /// <summary>
        /// 新增頁面間傳遞數據到WebCache
        
/// </summary>
        /// <returns>返回PageKeyID,用于頁面間傳遞的鍵值</returns>
        public static string InsertPageParams(string configKey, object obj,string pageKey)
        {
            
string result = null;

            MyWebCacheServiceClient cacheClient 
= CacheClientFactory.GetWebCacheServiceClient(REGION, SUB_REGION, configKey);
            cacheClient.Insert(
                MyWebCacheServiceClient.BuildKey(configKey,pageKey),
                obj,
                REGION,
                SUB_REGION);

            
return result;
        }
        
/// <summary>
        /// 從Cache里獲取頁面傳遞Cache
        
/// </summary>
        /// <param name="key">FlightCacheKey里的常量</param>
        /// <param name="pageKeyID">頁面傳遞的鍵值</param>
        public static object GetPageParams(string configKey, string pageKey)
        {
            
object result = null;
            MyWebCacheServiceClient cacheClient 
= CacheClientFactory.GetWebCacheServiceClient(REGION,
                SUB_REGION, configKey);
            result 
= cacheClient.Get(
                MyWebCacheServiceClient.BuildKey(configKey, pageKey),
                REGION,
                SUB_REGION);

            
return result;

        }
        
#endregion
    }

        兩級緩存類結構圖:

        以上代碼貼出來看起來有點亂,這里貼出網站兩級緩存類結構圖:

         

2
0
 
標簽:網站架構
 
 

文章列表

全站熱搜
創作者介紹
創作者 大師兄 的頭像
大師兄

IT工程師數位筆記本

大師兄 發表在 痞客邦 留言(0) 人氣()