zoukankan      html  css  js  c++  java
  • nopCommerce架构分析系列(二)数据Cache

    原文(http://www.cnblogs.com/gusixing/archive/2012/04/12/2443799.html)非常感谢作者顾思行的分享!

    序言

    在很多访问量较大的系统中,尤其在某一项数据访问频次较高时,我们会考虑使用缓存,减少系统和数据库的交互,以达到良好的用户体验。缓存主要有页面缓存和数据缓存。数据缓存的实现有很多方式,有基于memcached的,还有基于.net 4.0数据缓存框架,还有一些其他的实现方式。院子里有 PetterLiumemcached快递上手之C#,有兴趣的可以查看,本文主要讨论的是基于.net 4.0 数据缓存框架.

    数据缓存的实现原理

    nopCommerce项目中有两类的数据缓存,一个是全局数据缓存MemoryCacheManager,是用.net 4.0数据缓存框架实现的。另一个是页面请求级的数据缓存PerRequestCacheManager是基于HttpContextBase实现的。

    1、数据缓存框架是.net 4.0框架中新增的功能,详细了解.net 4.0  的缓存功能请看阿不写的全面认识一下.NET 4.0的缓存功能

    图1 部分缓存框架相关的类

    2、基于HttpContextBase页面请求级数据缓存

    HttpContextBase 类为抽象类,该类包含的成员与 HttpContext 类相同。 使用 HttpContextBase 类可以创建一些派生类,这些派生类与

    HttpContext 类相似,但是可以进行自定义并在 ASP.NET 管道外部使用。 在执行单元测试时,通常使用派生类实现具有自定义行为的成员以实现正在测试的方案,这更容易进行单元测试。HttpContextWrapper 类是从 HttpContextBase 类派生的。 HttpContextWrapper 类用作 HttpContext 类的包装。 在运行时,通常使用 HttpContextWrapper 类的实例调用 HttpContext 对象上的成员。

    HttpContext的Items集合是IDictionary键/值对的对象集合,在HttpRequest的生存期中共享。存储成本很高的调用的结果,防止该调用在页面上出现多次。一个HttpRequest中的各个单元需要处理相同或类似的数据。如果数据的生存期只是一个请求,就可以考虑使用HttpContext. Items作为短期的高速缓存。

    nopCommerce项目中的缓存

    1、缓存的实现

    nopCommerce项目缓存类层级图

    ICacheManager接口,该接口定义了数据缓存常用的方法。 

     1 public interface ICacheManager
     2     {
     3         /// <summary>
     4         /// Gets or sets the value associated with the specified key.
     5         /// </summary>
     6         /// <typeparam name="T">Type</typeparam>
     7         /// <param name="key">The key of the value to get.</param>
     8         /// <returns>The value associated with the specified key.</returns>
     9         T Get<T>(string key);
    10 
    11         /// <summary>
    12         /// Adds the specified key and object to the cache.
    13         /// </summary>
    14         /// <param name="key">key</param>
    15         /// <param name="data">Data</param>
    16         /// <param name="cacheTime">Cache time</param>
    17         void Set(string key, object data, int cacheTime);
    18 
    19         /// <summary>
    20         /// Gets a value indicating whether the value associated with the specified key is cached
    21         /// </summary>
    22         /// <param name="key">key</param>
    23         /// <returns>Result</returns>
    24         bool IsSet(string key);
    25 
    26         /// <summary>
    27         /// Removes the value with the specified key from the cache
    28         /// </summary>
    29         /// <param name="key">/key</param>
    30         void Remove(string key);
    31 
    32         /// <summary>
    33         /// Removes items by pattern
    34         /// </summary>
    35         /// <param name="pattern">pattern</param>
    36         void RemoveByPattern(string pattern);
    37 
    38         /// <summary>
    39         /// Clear all cache data
    40         /// </summary>
    41         void Clear();
    42     }

    CacheExtensions扩展方法对ICacheManager进行扩展。

     1 /// <summary>
     2     /// Extensions
     3     /// </summary>
     4     public static class CacheExtensions
     5     {
     6         public static T Get<T>(this ICacheManager cacheManager, string key, Func<T> acquire)
     7         {
     8             return Get(cacheManager, key, 60, acquire);
     9         }
    10 
    11         public static T Get<T>(this ICacheManager cacheManager, string key, int cacheTime, Func<T> acquire) 
    12         {
    13             if (cacheManager.IsSet(key))
    14             {
    15                 return cacheManager.Get<T>(key);
    16             }
    17             else
    18             {
    19                 var result = acquire();
    20                 //if (result != null)
    21                     cacheManager.Set(key, result, cacheTime);
    22                 return result;
    23             }
    24         }
    25     }

    MemoryCacheCache类,使用.net  缓存框架实现数据缓存

     1 /// <summary>
     2     /// Represents a MemoryCacheCache
     3     /// </summary>
     4     public partial class MemoryCacheManager : ICacheManager
     5     {
     6         protected ObjectCache Cache
     7         {
     8             get
     9             {
    10                 return MemoryCache.Default;
    11             }
    12         }
    13         
    14         /// <summary>
    15         /// Gets or sets the value associated with the specified key.
    16         /// </summary>
    17         /// <typeparam name="T">Type</typeparam>
    18         /// <param name="key">The key of the value to get.</param>
    19         /// <returns>The value associated with the specified key.</returns>
    20         public T Get<T>(string key)
    21         {
    22             return (T)Cache[key];
    23         }
    24 
    25         /// <summary>
    26         /// Adds the specified key and object to the cache.
    27         /// </summary>
    28         /// <param name="key">key</param>
    29         /// <param name="data">Data</param>
    30         /// <param name="cacheTime">Cache time</param>
    31         public void Set(string key, object data, int cacheTime)
    32         {
    33             if (data == null)
    34                 return;
    35 
    36             var policy = new CacheItemPolicy();
    37             policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);
    38             Cache.Add(new CacheItem(key, data), policy);
    39         }
    40 
    41         /// <summary>
    42         /// Gets a value indicating whether the value associated with the specified key is cached
    43         /// </summary>
    44         /// <param name="key">key</param>
    45         /// <returns>Result</returns>
    46         public bool IsSet(string key)
    47         {
    48             return (Cache.Contains(key));
    49         }
    50 
    51         /// <summary>
    52         /// Removes the value with the specified key from the cache
    53         /// </summary>
    54         /// <param name="key">/key</param>
    55         public void Remove(string key)
    56         {
    57             Cache.Remove(key);
    58         }
    59 
    60         /// <summary>
    61         /// Removes items by pattern
    62         /// </summary>
    63         /// <param name="pattern">pattern</param>
    64         public void RemoveByPattern(string pattern)
    65         {
    66             var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
    67             var keysToRemove = new List<String>();
    68 
    69             foreach (var item in Cache)
    70                 if (regex.IsMatch(item.Key))
    71                     keysToRemove.Add(item.Key);
    72 
    73             foreach (string key in keysToRemove)
    74             {
    75                 Remove(key);
    76             }
    77         }
    78 
    79         /// <summary>
    80         /// Clear all cache data
    81         /// </summary>
    82         public void Clear()
    83         {
    84             foreach (var item in Cache)
    85                 Remove(item.Key);
    86         }
    87     }

    PerRequestCacheManager类,实现页面请求级的数据缓存。

      1 /// <summary>
      2     /// Represents a NopStaticCache
      3     /// </summary>
      4     public partial class PerRequestCacheManager : ICacheManager
      5     {
      6         private readonly HttpContextBase _context;
      7 
      8         /// <summary>
      9         /// Ctor
     10         /// </summary>
     11         /// <param name="context">Context</param>
     12         public PerRequestCacheManager(HttpContextBase context)
     13         {
     14             this._context = context;
     15         }
     16         
     17         /// <summary>
     18         /// Creates a new instance of the NopRequestCache class
     19         /// </summary>
     20         protected IDictionary GetItems()
     21         {
     22             if (_context != null)
     23                 return _context.Items;
     24 
     25             return null;
     26         }
     27 
     28         /// <summary>
     29         /// Gets or sets the value associated with the specified key.
     30         /// </summary>
     31         /// <typeparam name="T">Type</typeparam>
     32         /// <param name="key">The key of the value to get.</param>
     33         /// <returns>The value associated with the specified key.</returns>
     34         public T Get<T>(string key)
     35         {
     36             var items = GetItems();
     37             if (items == null)
     38                 return default(T);
     39 
     40             return (T)items[key];
     41         }
     42 
     43         /// <summary>
     44         /// Adds the specified key and object to the cache.
     45         /// </summary>
     46         /// <param name="key">key</param>
     47         /// <param name="data">Data</param>
     48         /// <param name="cacheTime">Cache time</param>
     49         public void Set(string key, object data, int cacheTime)
     50         {
     51             var items = GetItems();
     52             if (items == null)
     53                 return;
     54 
     55             if (data != null)
     56             {
     57                 if (items.Contains(key))
     58                     items[key] = data;
     59                 else
     60                     items.Add(key, data);
     61             }
     62         }
     63 
     64         /// <summary>
     65         /// Gets a value indicating whether the value associated with the specified key is cached
     66         /// </summary>
     67         /// <param name="key">key</param>
     68         /// <returns>Result</returns>
     69         public bool IsSet(string key)
     70         {
     71             var items = GetItems();
     72             if (items == null)
     73                 return false;
     74             
     75             return (items[key] != null);
     76         }
     77 
     78         /// <summary>
     79         /// Removes the value with the specified key from the cache
     80         /// </summary>
     81         /// <param name="key">/key</param>
     82         public void Remove(string key)
     83         {
     84             var items = GetItems();
     85             if (items == null)
     86                 return;
     87 
     88             items.Remove(key);
     89         }
     90 
     91         /// <summary>
     92         /// Removes items by pattern
     93         /// </summary>
     94         /// <param name="pattern">pattern</param>
     95         public void RemoveByPattern(string pattern)
     96         {
     97             var items = GetItems();
     98             if (items == null)
     99                 return;
    100 
    101             var enumerator = items.GetEnumerator();
    102             var regex = new Regex(pattern, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
    103             var keysToRemove = new List<String>();
    104             while (enumerator.MoveNext())
    105             {
    106                 if (regex.IsMatch(enumerator.Key.ToString()))
    107                 {
    108                     keysToRemove.Add(enumerator.Key.ToString());
    109                 }
    110             }
    111 
    112             foreach (string key in keysToRemove)
    113             {
    114                 items.Remove(key);
    115             }
    116         }
    117 
    118         /// <summary>
    119         /// Clear all cache data
    120         /// </summary>
    121         public void Clear()
    122         {
    123             var items = GetItems();
    124             if (items == null)
    125                 return;
    126 
    127             var enumerator = items.GetEnumerator();
    128             var keysToRemove = new List<String>();
    129             while (enumerator.MoveNext())
    130             {
    131                 keysToRemove.Add(enumerator.Key.ToString());
    132             }
    133 
    134             foreach (string key in keysToRemove)
    135             {
    136                 items.Remove(key);
    137             }
    138         }
    139     }

    NopNullCache类,空的数据缓存类。

     1 /// <summary>
     2     /// Represents a NopNullCache
     3     /// </summary>
     4     public partial class NopNullCache : ICacheManager
     5     {
     6         /// <summary>
     7         /// Gets or sets the value associated with the specified key.
     8         /// </summary>
     9         /// <typeparam name="T">Type</typeparam>
    10         /// <param name="key">The key of the value to get.</param>
    11         /// <returns>The value associated with the specified key.</returns>
    12         public T Get<T>(string key)
    13         {
    14             return default(T);
    15         }
    16 
    17         /// <summary>
    18         /// Adds the specified key and object to the cache.
    19         /// </summary>
    20         /// <param name="key">key</param>
    21         /// <param name="data">Data</param>
    22         /// <param name="cacheTime">Cache time</param>
    23         public void Set(string key, object data, int cacheTime)
    24         {
    25         }
    26 
    27         /// <summary>
    28         /// Gets a value indicating whether the value associated with the specified key is cached
    29         /// </summary>
    30         /// <param name="key">key</param>
    31         /// <returns>Result</returns>
    32         public bool IsSet(string key)
    33         {
    34             return false;
    35         }
    36 
    37         /// <summary>
    38         /// Removes the value with the specified key from the cache
    39         /// </summary>
    40         /// <param name="key">/key</param>
    41         public void Remove(string key)
    42         {
    43         }
    44 
    45         /// <summary>
    46         /// Removes items by pattern
    47         /// </summary>
    48         /// <param name="pattern">pattern</param>
    49         public void RemoveByPattern(string pattern)
    50         {
    51         }
    52 
    53         /// <summary>
    54         /// Clear all cache data
    55         /// </summary>
    56         public void Clear()
    57         {
    58         }
    59     }

    2、缓存的应用

    下面是BlogService类中的CRUD,从中我们可以了解到,数据缓存是如何处理的,在数据检索时,直接从缓存取数据,其他方法均根据相关正则表达式移除BlogPost的所有缓存,以避免读取到脏数据。

     1 /// <summary>
     2         /// Gets a blog post
     3         /// </summary>
     4         /// <param name="blogPostId">Blog post identifier</param>
     5         /// <returns>Blog post</returns>
     6         public virtual BlogPost GetBlogPostById(int blogPostId)
     7         {
     8             if (blogPostId == 0)
     9                 return null;
    10 
    11             string key = string.Format(BLOGPOST_BY_ID_KEY, blogPostId);
    12             return _cacheManager.Get(key, () =>
    13             {
    14                 var pv = _blogPostRepository.GetById(blogPostId);
    15                 return pv;
    16             });
    17         }
    18 
    19         /// <summary>
    20         /// Deletes a blog post
    21         /// </summary>
    22         /// <param name="blogPost">Blog post</param>
    23         public virtual void DeleteBlogPost(BlogPost blogPost)
    24         {
    25             if (blogPost == null)
    26                 throw new ArgumentNullException("blogPost");
    27 
    28             _blogPostRepository.Delete(blogPost);
    29 
    30             _cacheManager.RemoveByPattern(BLOGPOST_PATTERN_KEY);
    31 
    32             //event notification
    33             _eventPublisher.EntityDeleted(blogPost);
    34         }
    35 
    36 
    37         /// <summary>
    38         /// Inserts an blog post
    39         /// </summary>
    40         /// <param name="blogPost">Blog post</param>
    41         public virtual void InsertBlogPost(BlogPost blogPost)
    42         {
    43             if (blogPost == null)
    44                 throw new ArgumentNullException("blogPost");
    45 
    46             _blogPostRepository.Insert(blogPost);
    47 
    48             _cacheManager.RemoveByPattern(BLOGPOST_PATTERN_KEY);
    49 
    50             //event notification
    51             _eventPublisher.EntityInserted(blogPost);
    52         }
    53 
    54         /// <summary>
    55         /// Updates the blog post
    56         /// </summary>
    57         /// <param name="blogPost">Blog post</param>
    58         public virtual void UpdateBlogPost(BlogPost blogPost)
    59         {
    60             if (blogPost == null)
    61                 throw new ArgumentNullException("blogPost");
    62 
    63             _blogPostRepository.Update(blogPost);
    64 
    65             _cacheManager.RemoveByPattern(BLOGPOST_PATTERN_KEY);
    66 
    67             //event notification
    68             _eventPublisher.EntityUpdated(blogPost);
    69         }

    下面是nopCommerce中该部分的依赖注入部分:ps:nopCommerce的依赖注入会在以后为大家介绍:)

     1 //HTTP context and other related stuff
     2             builder.Register(c => 
     3                 //register FakeHttpContext when HttpContext is not available
     4                 HttpContext.Current != null ?
     5                 (new HttpContextWrapper(HttpContext.Current) as HttpContextBase) :
     6                 (new FakeHttpContext("~/") as HttpContextBase))
     7                 .As<HttpContextBase>()
     8                 .InstancePerHttpRequest();
     9             builder.Register(c => c.Resolve<HttpContextBase>().Request)
    10                 .As<HttpRequestBase>()
    11                 .InstancePerHttpRequest();
    12             builder.Register(c => c.Resolve<HttpContextBase>().Response)
    13                 .As<HttpResponseBase>()
    14                 .InstancePerHttpRequest();
    15             builder.Register(c => c.Resolve<HttpContextBase>().Server)
    16                 .As<HttpServerUtilityBase>()
    17                 .InstancePerHttpRequest();
    18             builder.Register(c => c.Resolve<HttpContextBase>().Session)
    19                 .As<HttpSessionStateBase>()
    20                 .InstancePerHttpRequest();
    21        //cache manager
    22             builder.RegisterType<MemoryCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_static").SingleInstance();
    23             builder.RegisterType<PerRequestCacheManager>().As<ICacheManager>().Named<ICacheManager>("nop_cache_per_request").InstancePerHttpRequest();

    有何改进指出?

    在缓存具体实现的时候,除了检索方法,其他的CRUD方法,均删除了所有同类的数据缓存,我们是不是可以这样想,上面的BlogPost肯定是有主键的,我们可以根据主键对缓存里面数据进行相关的操作,而不是在增删改的时候,移除所有的BlogPost缓存。

    总结

    在我们的系统中,根据需要去判断是否需要去设置缓存,采用何种方式去实现缓存?nopCommerce项目中给我提供了很好的例子,在实际应用可以借鉴其实现方式,增强我们系统的用户体验。

    相关资料:

    1、为短时间状态存储应用HttpContext.Current.Items

    2、全面认识一下.NET 4.0的缓存功能

    3、HttpContext是干什么的

    4、为什么是HttpContextBase而不是IHttpContext

  • 相关阅读:
    zookeeper基础
    4. Zookeeper单机版安装
    3. 服务中间件Dubbo
    2. Maven工程的搭建
    Maven的优点
    应用架构的演进历史 MVC、 RPC、SOA 和 微服务架构
    js 正则表达式验证
    后台正则表达式验证部分部分总结
    Linux下记录登录用户历史操作
    Django使用Ace实现在线编辑器
  • 原文地址:https://www.cnblogs.com/ghw0501/p/4733436.html
Copyright © 2011-2022 走看看