6. 缓存 - 《APS.NET本质论》

CaChe是ASP.NET中唯一可以根据服务器使用情况,动态管理内存使用的状态管理方案。我们通过每个缓存数据的键值字符串来区分缓存的数据。

简单案例来说。将数据从数据库/文件取出放在服务器内存中,后来的用户获取数据,不用查询数据而直接从内存中获取,提高了访问速度,减轻服务器的压力。——经常查询,不经常改动

题外话,分布式缓存:MemcacheRedis等。(现在的大数据项目需要用到这些)

   

1.1 缓存的原理

缓存需要注意以下几点

   

  1. 缓存的空间是有限的。
  2. 缓存的内容可能会失效,原因:
  • 绝对过期。在特定的时间点后,缓存数据失效,例如天气预报。
  • 活动过期。在一个时间间隔之内,如果数据没有使用,那么,数据将过期。
  • 缓存依赖

    缓存数据依赖于某个对象,例如文件系统中的文件或者文件夹,数据库中的数据等,当被依赖的对象发生变化,缓存的数据将成为脏数据。

  • 优先级。当缓存空间不够的时候,其他条件相同的情况下,通过优先级判断哪些数据需要从缓存中跑起掉。
  1. 通过移除通知,当缓存的数据被从缓存中移除的时候,可以通知应用程序。应用程序需要写一个符合特定委托的方法,以便接收通知。
  2. 由于内存有限,所以不太可能将所有数据缓存到内存中,因此,Cache 必须对缓存的数据进行有效的调度,以达到内存使用效率的最大化。

   

1.2 .NET 中缓存管理实现

在.NET中缓存的定义命名空间是 System.Web.Cachine

   

  1. Dependency 依赖:
  • .NET 中支持两种依赖:CacheDependency 和 SqlDependency。从.NET 2.0 开始,CacheDependency 不再密封,而是可以继承。

    CacheDependency :表示对文件或目录的依赖。

    SqlDependency :表示对 SQL 数据库的依赖。
     

  • 过期时间:过期时间分为绝对过期时间和滑动过期时间。(只能二选一)
    绝对过期时间为一个特定的时间点,类型是
    DateTime,如果不使用绝对过期时间,那么,使用 System.Web.Caching.Cache.
    • 绝对过期时间为一个特定的时间点,类型是 DateTime,如果不使用绝对过期时间,那么,使用 System.Web.Caching.Cache.NoAbsoluteExpiration 表示。
    • 滑动过期时间为一个时间间隔,类型为 TimeSpan,如果不使用滑动过期时间,使用 System.Web.Cachine.NoSlidingExpiration 表示。
       
  1. 优先级 CacheItemPrority

    由于我们需要缓存大量的数据,在内存有限的情况下,就必须对缓存的数据进行优先级分类,重要的数据可以更长时间保存在内存中。CacheItemPriority 是一个枚举类型,从高到低定义了如下优先级:

  • NotRemoveable,最高优先级,不会因为内存调整被移除,除非过期或者缓存依赖被清除。
  • High,服务器释放内存时,最不可能被移除
  • AboveNormal,被移除的可能性比 Normal 小
  • Normal,具有该级别的数据很可能被移除。
  • Default,就是 Normal 级别
  • BelowNormal,具有该优先级的数据比 Normal 级别更有可能移除。
  • Low,此级别的数据最可能被移除。
     
  1. 删除通知:

    .NET 提供了一个机制,当被缓存的数据从内存中移除的时候,可以提供一个通知机制,来回调用户定义的方法,方法必须符合 CacheItemRemovedCallback 委托的定义。
     

    public delegate void CacheItemRemovedCallback {  

      string key,  

      Object value,  

      CacheItemRemovedReason reason  

    }  


    其中,
    CacheItemRemovedReason 未婚村被移除的原因。CacheItemRemovedReason 是一个枚举类型,
    定义了如下原因:

    DependencyChanged,由于依赖发生变化被移除。

    Expired,由于过期被移除。

    Removed,由于调用 Insert 插入一个同名的缓存项或者调用 Remove 失效被移除。

    Underused,系统移除。
     

  2. 特别注意:

    回调的时机是不可预测的,不能假定回调发生时,回调方法的执行线程存在 HttpContext 的上下文,为了在没有请求上下文的时候取得对 Cache 对象的引用,可以通过 HttpRuntime Cache 属性来使用应用程序的 Cache 。

  • 不能在页面上使用实例方法来作为回调方法,当在页面上使用回调方法时,由于指向回调方法的引用会阻止垃圾回收机制,因此会造成内存很快消耗光。
  • 一般通过在自定义类的静态方法实现回调方法,或使用页面对象的静态方法实现。

   

1.3.基于文件的缓存依赖

 

CacheDependency 表示依赖对于文件或者目录的依赖。

 

Public class CacheDependency : Idisposable

   

通过改变文件的更新日期来清除缓存。

   

public static string Message  

{  

get {

    HttpContext context = System.Web.HttpContext.Current;  

    

    string message = context.Cache["Message"] as string;  

    

    if (message == null)  

    {  

        string path = context.Server.MapPath("~/TextFile.txt");  

        message = System.IO.File.ReadAllText(path);  

    

        context.Cache.Add(  

            "Message",  

            message,  

            new CacheDependency(path),  

            Cache.NoAbsoluteExpiration,  

            new TimeSpan(100),  

            CacheItemPriority.Normal,  

            CallBack  

            );  

    }  

    return message;  

}  

}

    

/// <param name="reason">原因</param>  

private static void CallBack(string key, Object value, CacheItemRemovedReason reason)  

{  

    //但是需要注意的是,此时不一定有请求  

    //因此,不能使用 HttpContext  

    

    //如果需要使用 Cache  

    //可以通过 System.Web.HttpRuntime.Cache 来获取当前网站应用程序的 Cache  

}  

   

Cache.Insert Cache.Add 区别 

   

1.4 基于 SQL 的缓存依赖

当数据库信息变化时,应用程序获取变化的通知是缓存依赖得以实现的基础。

  • 数据库通知:

    当数据库中信息变化,主动通知应用程序。

  • 轮询:

    数据库不能通知的时候,应用程序主动定期访问数据库,检查数据变化。

微软从 SQL Server 2005开始提供数据库通知。如果数据库不支持通知机制,那么只能通过轮询来实现。

但是轮询不可能再次查询一遍进行比较,我们通常通过触发器来实现。

   

轮询的方法:

sqlCacheDependency 的 enabled 属性为真,表示启动轮询,pollTime,毫秒为单位,意识是每隔2秒检测下数据库,检测表是否有发生变化。connectionStringName为数据库链接字符串。

   

<connectionStrings>       

    <add name="Am_WeixinWeb" connectionString="data source=192.168.1.200;initial catalog=Am_WeixinWeb;uid=sa;password=lh1234;"  />  

  </connectionStrings>  

   

<system.web>  

  <caching>  

    <sqlCacheDependency enabled="true" pollTime="2000">  

      <databases>  

        <add name="Test" connectionStringName="Am_WeixinWeb" />  

      </databases>  

    </sqlCacheDependency>  

  </caching>  

   

SqlCacheDependency 表示 SQL 缓存依赖对象,即支持通知机制也可以支持轮询机制。

创建 SqlCacheDependency 对象的方法如下:

   

SqlCacheDependency dep = new SqlCacheDependency("Test""Am_recProScheme");  //Test对应配置项的缓存配置key ,后面是数据库表名  

   

如果使用 SQL 2005 以及后面的版本,可以使用通知机制。

   

Alter database 数据库名称 set enable_broker  

   

然后,定义一个有效的查询对象来获取数据库的查询通知。SqlCommand 必须满足如下要求:

表名必须包括所有者名称的完全限定名;

Select 显式指定列名,不能使用 * 来选择所有列。

   

SqlCommand command = new SqlCommand(connectionString,sql);  

   

最后,构造 SQL 缓存依赖对象,

   

SqlCacheDependency scd = new SqlCacheDependency (command);  

   

如果使用通知机制,不需要使用工具在数据库中做准备工作,也不需要在配置文件中设置轮询。

   

1.5 组合的缓存依赖

当依赖的内容为多个 Denpendency (可能是 CacheDependency 或者 SqlDependency)时,可以通过 AggregateCacheDependency 创建依赖的组合,在任何一个依赖项变化时,使缓存失效。

   

1.6 删除所有缓存项目

Cache 中没有内建清除全部项目的方法。所以必须遍历这个集合,去的其中的 Key 的集合,然后再遍历所有的 Key ,使用 Key 删除缓存项目。

   

1.7 Web 服务器端的页面缓存

   

1.8 页面局部缓存

页面部分缓存是将页面部分内容保存在内存中以便响应用户请求。两种:

1.用户控件缓存

在用户控件中的 OutputCache 指令支持选项:

  • Duration
  • VaryByParam
  • VaryByControl
  • VaryByCustom
  • VaryByContentEncodings
  • Shared
  • SqlDenpendcy

   

2.缓存后替换

大部分内容需要缓存,某些片断内容是动态的。

例如新闻页面,新闻内容大部分时间不变,但是页面显示的当前时间、广告信息等需要随时变化。

缓存后替换:将整个页面输出缓存,将特定部分标记为不缓存。

三种方式:

  • 声明的方式使用 Substitution 控件
  • 编程的方式使用 Substitution 控件
  • 使用 Adrotor 控件

   

* 1.9 自定义的输出缓存提供器

.NET 4.0 之前使用 System.Web.Caching.Cache4.0 之后重新进行了设计,提供一个 OutputCacheProvider 供开发人员扩展。默认情况,还是使用 System.Web.Caching.Cache

   

题外:2.1 Memcached 分布式内存对象缓存系统

自己搜索。

   

参考:

  1. http://www.cnblogs.com/knowledgesea/p/3904929.html asp.net缓存 - 张龙豪
  2. ASP.NET 本质论》郝冠军
posted @ 2017-03-15 23:19  【唐】三三  阅读(253)  评论(0编辑  收藏  举报