`
javatome
  • 浏览: 826876 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

网站架构之缓存应用(2)实现篇

阅读更多

上一篇我主要总结了网站缓存中的一些基本概念,以及我对于网站架构缓存应用的架构实现思路,这篇主要分享下如何利用微软企业库来实现一二级缓存的缓存服务。
   
    为了能够有效的管理缓存,需要对使用缓存方法上做一些规范,即要想使用缓存组件提供的服务,需要在指定的配置文件中按照一定的规则来配置缓存条目,不允许在配置之处使用缓存。下面先展示下一条Cache条目的配置:

代码
< Region  name ="MyBlog" >
    
< SubRegion  name ="default" >    
      
< Cache  CacheMode ="LocalCacheOnlyMode"  Key ="BlogListConfigKey"  BufferType ="AbsoluteTime"  BufferTimeSeconds ="300"  CacheType ="AbsoluteTime"  CacheTimeMinutes ="30"  CachePriority ="Normal" />      
    
</ SubRegion >
  
</ Region >

 

   
     上面的代码中,其实由三部分构成:
     1:主分区:Regin,如果一个网站分很多子系统,可以为每个子系统定义一个这样的主分区,例如食品频道Food,手机频道Mobile等;
     2:子分区:SubRegion,主分区下面的子分区,即对子系统更加小的划分,可以根据子系统的功能来划分,例如产品列表页List,详细页Detail等;
     3:缓存条目:Cache,指具体的一则缓存条目规则,这里的缓存条目规则并不是指某一条缓存设置,而是指一条缓存规则,与具体的缓存条目是一对多的关系。
        <1>:CacheMode,设置缓存模式,是只有二级缓存还是即有一级缓存也有二级缓存,例如用户页面之间的信息沟通就只需要二级缓存,即 缓存在web server上。而产品列表页的数据属于全局数据,就需要即采用二级缓存也需要一级缓存。
        <2>:BufferType,指二级缓存的过期方式,分为绝对过期,滑动过期,文件依赖。
        <3>:BufferTimeSeconds,二级缓存Timespan中的秒。
        <4>:CacheType,一级缓存的过期方式,类型同BufferType.
        <5>:CacheTimeMinutes,一级缓存Timespan中的分钟。
        <6>:CachePriority,缓存的优先级。


     二级缓存实现:
     第一:IWebCacheProvider,缓存提供者接口,它公布了所有缓存组件需要的方法,接口之所以加上了ServeiceContract标签, 是由于下面的一级缓存WCF服务也继承此接口的原因。小提示:WCF服务契约对于方法重载的实现和普通方式有小小区别,请注意 OperationContract标签的定义。

代码
 [ServiceContract]
    
public    interface  IWebCacheProvider
    {
        [OperationContract(Name 
=   " Add " )]
        
void  Insert( string  key,  object  value,  string  region,  string  subRegion);

        [OperationContract(Name 
=   " AddByAbsoluteTime " )]
        
void  Insert( string  key,  object  value,  string  region,  string  subRegion, MyCacheItemPriority scavengingPriority, AbsoluteTimeCacheDependency absoluteTimeCacheDependency);

        [OperationContract(Name 
=   " AddBySlidingTime " )]
        
void  Insert( string  key,  object  value,  string  region,  string  subRegion, MyCacheItemPriority scavengingPriority, SlidingTimeCacheDependency slidingTimeCacheDependency);

        [OperationContract(Name 
=   " AddByFile " )]
        
void  Insert( string  key,  object  value,  string  region,  string  subRegion, MyCacheItemPriority scavengingPriority, FileCacheDependency fileCacheDependency);

        [OperationContract]
        
void  Delete( string  key,  string  region,  string  subRegion);

        [OperationContract]
        
object  Get( string  key,  string  region,  string  subRegion);

        [OperationContract]
        
void  Clear( string  region);

        [OperationContract]
        
int  Count( string  region);
    }

 

    
    第二:EntLibWebCacheProvider,微软企业库实现缓存实现类。代码并不贴了,基本就是利用企业库的缓存组件实现上面的接口。
   
     第三:MyWebCacheServiceClient,提供缓存客户端的实例。包含了两个重要的属性:一级缓存实例,二级缓存实例。余下的就是调用 EntLibWebCacheProvider来完成缓存的调用,以及根据缓存规则,选择操作一级缓存以及二级缓存。

           说明:下面代码中的GetMemcachedWebCacheProvider是下篇文章会提到的利用memcached实现一级缓存,由于需要支持一级缓存在企业库以及memcached之间的切换才出现的逻辑。

代码
       // 一级缓存
        IWebCacheProvider PrimaryCacheProvider;
        
// 二级缓存
        IWebCacheProvider SecondaryCacheProvider;
         
///   <summary>
        
///  实例化二级缓存
        
///   </summary>
        
///   <param name="configFilePath"></param>
        
///   <returns></returns>
         private  IWebCacheProvider GetSecondaryCacheProvider()
        {
            IWebCacheProvider provider 
=   null ;
            provider 
=  WebCacheProviderFactory.GetEntLibWebCacheProvider(configFilePath);
            
return  provider;
        }
        
///   <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;
        }

 

        
       一级缓存的实现: 由于一级缓存也采用微软企业库实现,而企业库本身是不具备分布式功能的,就算是memcached,本身也不具备分布式,而在于客户端的实现,所以企业库我们也可以实现分布式。
        首先:我们把实现了缓存的组件以WCF服务形式分布出来,在多个服务器上部署,形成一个服务器群;
        其实:实现分布式的客户端,让服务的请求均匀的分布到之前部署的WCF缓存服务器上。这里采用一致性hash算法实现,主要是根据key的hash值以及服务器数量来选择存储的服务器,这里贴些主要的实现代码,供参考:
        
        1:定义一个hash的服务器实例集合,为每个服务器分配250个hash值,这里的值可以根据实际情况调整。

private  Dictionary < uint , isRoc.Common.Cache.CacheProvider.IWebCacheProvider >  hostDictionary;

 

        2:定义一个hash的服务实例key集合,用来统计所有服务器实例中的hash key。  

private   uint [] hostKeysArray;

 

        3:创建服务器列表的hash值。 

代码
///   <summary>
        
///  重新设置服务器列表
        
///   </summary>
        
///   <param name="hosts"> 服务器列表 </param>
         internal   void  Setup(List < WebCacheServerInfo >  hosts)
        {
            hostDictionary 
=   new  Dictionary < uint , isRoc.Common.Cache.CacheProvider.IWebCacheProvider > ();
            List
< isRoc.Common.Cache.CacheProvider.IWebCacheProvider >  clientList  =   new  List < isRoc.Common.Cache.CacheProvider.IWebCacheProvider > ();
            List
< uint >  hostKeysList  =   new  List < uint > ();
            
foreach  (WebCacheServerInfo host  in  hosts)
            {
                
// 创建客户端

                isRoc.Common.Cache.CacheProvider.IWebCacheProvider client 
=  ServiceProxyFactory.Create < isRoc.Common.Cache.CacheProvider.IWebCacheProvider > (host .HostUri );
                
// Create 250 keys for this pool, store each key in the hostDictionary, as well as in the list of keys.
                 for  ( int  i  =   0 ; i  <   250 ; i ++ )
                {
                    
uint  key  =   0 ;
                    
switch  ( this .HashAlgorithm)
                    {
                        
case  EHashAlgorithm.KetamaHash:
                            key 
=  ( uint )Math.Abs(KetamaHash.Generate(host.HostUri  +   " - "   +  i));
                            
break ;
                        
case  EHashAlgorithm.FnvHash32:
                            key 
=  BitConverter.ToUInt32( new  ModifiedFNV1_32().ComputeHash(Encoding.UTF8.GetBytes(host.HostUri  +   " - "   +  i)),  0 );
                            
break ;
                    }

                    
if  ( ! hostDictionary.ContainsKey(key))
                    {
                        hostDictionary.Add(key, client);
                        hostKeysList.Add(key);
                    }
                }

                clientList.Add(client);
            }

            
// Hostlist should contain the list of all pools that has been created.
            clientArray  =  clientList.ToArray();

            
// Hostkeys should contain the list of all key for all pools that have been created.
            
// This array forms the server key continuum that we use to lookup which server a
            
// given item key hash should be assigned to.
            hostKeysList.Sort();
            hostKeysArray 
=  hostKeysList.ToArray();

        }

 

        4:如何根据key值来查找具体的缓存服务实例呢,即具体的key存储在哪一台服务器上呢?根据传入的key值,计算出对应的hash值,然后经过特定的算法计算出服务器实例地址。

代码
  internal  isRoc.Common.Cache.CacheProvider.IWebCacheProvider GetServiceClient( uint  hash)
        {
            
// Quick return if we only have one host.
             if  (clientArray.Length  ==   1 )
            {
                
return  clientArray[ 0 ];
            }

            
// New "ketama" host selection.
             int  i  =  Array.BinarySearch(hostKeysArray, hash);

            
// If not exact match...
             if  (i  <   0 )
            {
                
// Get the index of the first item bigger than the one searched for.
                i  =   ~ i;

                
// If i is bigger than the last index, it was bigger than the last item = use the first item.
                 if  (i  >=  hostKeysArray.Length)
                {
                    i 
=   0 ;
                }
            }
            
return  hostDictionary[hostKeysArray[i]];
        }

 

        
        总结:本文简单的介绍了如何利用微软企业库来实现具有两级缓存的缓存组件,上篇我提到过,实现一级缓存也可以采用memcached,采用 memcached可以不用自己开发分布式客户端,目前有两个成熟的解决方 案:1:Memcached.ClientLibrary2:EnyimMemcached。下篇我来介绍一级缓存如何通过memcached实现,以及 如何让组件在一级缓存上即支持企业库也支持memcached。

1
1
分享到:
评论

相关推荐

    低清版 大型门户网站是这样炼成的.pdf

    1.2 高性能、高负载门户网站架构剖析 9 1.2.1 服务器操作系统的选择 10 1.2.2 dns服务器bind 16 1.2.3 cache服务器squid 18 1.2.4 带负载均衡的http服务器apache 19 1.2.5 支持集群功能的web服务器tomcat 21 ...

    亮剑.NET深入体验与实战精要2

    6.5 项目案例1:实现网站的RSS应用 267 6.6 项目案例2:在线实现RSS阅读器 270 本章常见技术面试题 275 常见面试技巧之经典问题巧回答 275 本章小结 276 第7章 Web Service开发详解 277 7.1 Web Service基本概念 278...

    asp.net知识库

    如何在.NET中实现脚本引擎 (CodeDom篇) .NET的插件机制的简单实现 我对J2EE和.NET的一点理解 难分难舍的DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] ...

    亮剑.NET深入体验与实战精要3

    6.5 项目案例1:实现网站的RSS应用 267 6.6 项目案例2:在线实现RSS阅读器 270 本章常见技术面试题 275 常见面试技巧之经典问题巧回答 275 本章小结 276 第7章 Web Service开发详解 277 7.1 Web Service基本概念 278...

    (全)传智播客PHP就业班视频完整课程

    10-20 2 smarty应用 更换网站皮肤2 10-20 3 smarty应用 更换网站皮肤3 10-20 4 smarty应用 更换网站皮肤4 10-20 5 smarty二级联动 10-20 6 smarty完成静态化 10-20 7 10-20 8 smarty分页技术 10-20 9 10-22 1 ajax...

    史上最全韩顺平传智播客PHP就业班视频,10月份全集

    10-20 2 smarty应用 更换网站皮肤2 10-20 3 smarty应用 更换网站皮肤3 10-20 4 smarty应用 更换网站皮肤4 10-20 5 smarty二级联动 10-20 6 smarty完成静态化 10-20 7 10-20 8 smarty分页技术 10-20 9 10-22 1 ajax...

    史上最全传智播客PHP就业班视频课,8月份视频

    10-20 2 smarty应用 更换网站皮肤2 10-20 3 smarty应用 更换网站皮肤3 10-20 4 smarty应用 更换网站皮肤4 10-20 5 smarty二级联动 10-20 6 smarty完成静态化 10-20 7 10-20 8 smarty分页技术 10-20 9 10-22 1 ajax...

    韩顺平PHP JS JQUERY 所有视频下载种子 货真价实

    10-20 2 smarty应用 更换网站皮肤2 10-20 3 smarty应用 更换网站皮肤3 10-20 4 smarty应用 更换网站皮肤4 10-20 5 smarty二级联动 10-20 6 smarty完成静态化 10-20 7 10-20 8 smarty分页技术 10-20 9 10-22 1 ajax...

    史上最全韩顺平传智播客PHP就业班视频,9月份全集

    10-20 2 smarty应用 更换网站皮肤2 10-20 3 smarty应用 更换网站皮肤3 10-20 4 smarty应用 更换网站皮肤4 10-20 5 smarty二级联动 10-20 6 smarty完成静态化 10-20 7 10-20 8 smarty分页技术 10-20 9 10-22 1 ajax...

    PHP和MySQL WEB开发(第4版)

    1.2 创建一个示例应用:Bob汽车零部件商店 1.2.1 创建订单表单 1.2.2 表单处理 1.3 在HTML中嵌入PHP 1.3.1 使用PHP标记 1.3.2 PHP语句 1.3.3 空格 1.3.4 注释 1.4 添加动态内容 1.4.1 调用函数 1.4.2 使用date()函数...

    ElasticSearch5.2全网最全技术视频

    (2-1)大型电商搜索引擎,包括了真正复杂的大型企业,大型项目的商业级搜索引擎架构,包括了检索、数据更新、排序、分词、query分析等各个核心模块,同时架构上实现了复杂的缓存机制,热启动机制,防雪崩机制,...

    PHP和MySQL Web开发第4版pdf以及源码

    1.2 创建一个示例应用:Bob汽车零部件商店 1.2.1 创建订单表单 1.2.2 表单处理 1.3 在HTML中嵌入PHP 1.3.1 使用PHP标记 1.3.2 PHP语句 1.3.3 空格 1.3.4 注释 1.4 添加动态内容 1.4.1 调用函数 1.4.2 使用...

    PHP和MySQL Web开发第4版

    1.2 创建一个示例应用:Bob汽车零部件商店 1.2.1 创建订单表单 1.2.2 表单处理 1.3 在HTML中嵌入PHP 1.3.1 使用PHP标记 1.3.2 PHP语句 1.3.3 空格 1.3.4 注释 1.4 添加动态内容 1.4.1 调用函数 1.4.2 使用...

    看透springMvc源代码分析与实践

    第1章 网站架构及其演变过程2 1.1 软件的三大类型2 1.2 基础的结构并不简单3 1.3 架构演变的起点5 1.4 海量数据的解决方案5 1.4.1 缓存和页面静态化5 1.4.2 数据库优化6 1.4.3 分离活跃数据8 1.4.4 批量...

    集群好书《高性能Linux服务器构建实战》 试读章节下载

    由国内著名技术社区联合推荐的2012年IT技术力作:《高性能Linux服务器构建实战:运维监控、性能调优与集群应用》,即将上架发行,此书从Web应用、数据备份与恢复、网络存储应用、运维监控与性能优化、集群高级应用等...

    ASP.NET 2.0 跟我一起学Visual.Studio2005 2/9

    课程简介:应用程序性能永远是一个永恒的话题,Web应用或网站的用户总是希望网站的响应越快越好。一个好的设计师从产品的需求调研阶段就应该考虑性能问题。当然,在产品未开发时总是不能考虑的很完善,这时,功能...

    最近很火的分布式数据库 RethinkDB.zip

    能够最大化得益于RethinkDB实时推送架构的例子包括:协作网站和移动应用数据流分析应用多人在线游戏实时交易场所设备联机举个例子:在协作设计一个app的时候,其中一个用户改变了某个按钮的位置,服务器就必须在第一...

    淘特Asp.Net Cms(1.0)

    本系统使用三层架构,应用逻辑采用数据库Dao+对象工厂模式;系统采用UTF-8编码,支持多国语言,网站后台采用WEB标准排版,支持多浏览器。文章管理采用可视化的内容编辑,操作容易、上手简单,是一套不需要懂编程...

    HTML开发王

    第4篇 创建和发布网站篇 第17章 网页、网站和网络应用程序 17.1 安装和设置网络应用程序的运行环境 17.1.1 安装iis 17.1.2 安装pws 17.1.3 通过服务器请求网页 17.2 web服务器根目录和虚拟目录 17.2.1 web服务器根...

Global site tag (gtag.js) - Google Analytics