entlib2.0的研究(四)--使用缓存组件开发应用程序

 

2使用缓存组件进行开发

首先,解释如何配置,添加到你的解决方案中去,选择后端的存储器。接着,显示如何在特定场景中使用缓存组件。

2.1添加配置信息

 

注意:

这个版本的配制工具还没有发布,所以要改变配置,只能编辑XML文件,参考QuickStart和单元测试的配置文件。

 

2.2添加程序代码

完成由以下的几个步骤:

l         添加Microsoft.Practices.EnterpriseLibrary.Caching.dll的引用

l         添加Microsoft.Practices.EnterpriseLibrary.Common.dll的引用

l         using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

         using Microsoft.Practices.EnterpriseLibrary.Caching;

 

添加程序代码,通常有两步:

l         创建CacheManager对象

l         调用合适的方法

 

2.3选择合适的后端存储器

每个cache manager不能只有持久存储器而没有在内存中的存储器。在配置的时候指定持久的存储器。后端存储器可以使数据被保存,当应用程序重启的时候。默认提供两种持久后端存储器:

l         隔离存储

l         数据访问组件

 

注意:

一个应用程序可以使用多个缓存;每个缓存都会在配置中用一个cache manager表现。在多缓存的应用中,缓存组件不支持使用相同的持久化后端存储位置和别名。

 

使用空的后端存储

空的后端存储是默认的配置项。它不能持久化缓存项。缓存数据只能存在于内存中。这种适用于当应用重启你想从原始数据源中刷新缓存项的场景。

 

使用隔离的后端存储器

l         持久化是需要的,并且用户的数量比较小。

l         使用数据库不方便

 

隔离存储适用于smart clients和每一个服务端程序有自己的缓存。还有,隔离存储是通过用户隔离的,服务器必须模拟用户到应用的请求。

 

使用数据访问组件的后端存储

在数据库中存储缓存数据。现在,缓存组件包含创建需要数据库的脚本。现在只测试了SQL Server数据库,也可以使用其他数据库。每种数据库类型都必须有为数据访问组件的数据库提供者和兼容的结构。

每一个CacheManager对象运行于单一的应用程序域,必须使用不同的数据库部分。

 

服务端场景的考虑

一个cache manager不能在多个应用域中共享。服务端应用经常会被部署与多台计算机上,但他们有唯一的一个内存中缓存的备份。这对同一台机器上的多个进程也是一样的。

不同的应用程序不应该使用同一个数据访问后端存储实例和partition。这样会引起不可预料的结果。

当一个应用有多个进程时,你可以用下面三种的方法之一:

l         所有的实例使用同一个数据库实例,但是使用不同的partition

l         所有实例使用同一个数据库实例和相同的partition,所有的cache managers可以读写缓存。

l         所有实例使用同一个数据库实例和相同的partition,只有一个cache managers可以写缓存,其他的只能读。

 

 

场景一:分隔的缓存

在这种场景中,每一个cache manager的操作是互不依赖的。虽然使用同一个数据库实例,但是每一个缓存保存数据到不同的分隔中。事实上,每一个应用实例都有一个缓存。当一个应用程序重启了,每一个cache manager只要从自己的分隔中加载数据。

如果应用预载缓存,每一个部署的实例从原始的数据源中获取数据。预载的数据为每一个应用的实例使用一个后端的存储空间。这意味着,部署同一个应用程序到不同的进程不再比部署不同的应用程序高效。

部署同一个应用到不同的服务器,每一个配置块都是直接配置的,不能保证在每一个后端存储分隔中的数据都是相同的。内存中的缓存是随着一个特定的实例如何使用缓存来变换的。。因为应用的请求被路由到不同的服务器,在内存中的缓存也可能不同。这意味着即时所有的应用都同时重启,也不能保证他们有相同的内存缓存。

 

场景二:共享分隔

在这个场景中,每个应用的实例对唯一的一个内存中缓存进行操作。当一个应用创建了cache manager,将后端的存储填充到内存中。这意味着如果所有的实例同时重启,内存中将加载相同的数据。因为都使用同一个数据库分隔,每一个应用实例不需要附加的后端存储。

cache manager被创建是唯一数据从后端加载到内存中的情况。在这以后,内存中的缓存内容就完全由实例使用缓存的情况决定。内存中的缓存内容也是不一样的。

添加和移出缓存项,就会改变缓存中的内容。移出和清除过期的项也会引起这样的变化。变化产生时,cache manager会更新后端的存储。而后端的存储不会通知别的实例当他的内容改变了。因此,当一个实例改变了后端内容时,其他的实例会有不匹配于后端的内容。这意味着当一个应用重启时,他不能获取到重启前相同的内容。

如果订阅的事件,应用可以被通知缓存项过期,这是由cache manager提供的。应用可以使用这种通知来用原始的数据源刷新缓存。当应用刷新了缓存,cache manager也会用这个数据更新后端的存储。如果应用被部署到不同的电脑,,每一个实例可以接收到这个事件和从原始数据源中请求这一项的请求。多个请求对应用和数据源的性能又不好的影响。因为,使用通知来控制过期是不被推荐的。

 

场景三:单一的可写的cache manager

在这个场景中,只有一个实例可以对缓存进行写操作。这个可写的应用实例被称作主人。主人的缓存内容总是和后端存储一致的。其他实例只能有数据的镜像。因为没有刷新缓存的能力,他们的缓存会因为过期而失效。

 

2.4关键场景

2.4.1向缓存中添加项

缓存储存那些创建和传输开销很大的项。例如,在零售应用中,产品的列表必须从数据访问组件中传输到用户界面组件,使列表可以被展现给用户。为了增加性能,某些列表可能会被添加到缓存中。

 

目标

在这个场景中,添加项到缓存,设置过期周期和清除策略。

 

解决方案

使用CacheManagerAdd方法。如果不显式的设定过期策略,将使用默认的,默认设置是NeverExpirednormal。如果添加已经存在的key,将移出旧的,添加新的。如果在存储过程中出现错误,缓存被从存为原始状态。

 

使用Add方法

创建了product对象,设置清除优先级为2,过期不刷新,上次访问后5分钟后过期。

CacheManager productsCache = CacheFactory.GetCacheManager();

 

string id = "ProductOneId";

string name = "ProductXYName";

int price = 50;

 

Product product = new Product(id, name, price);

 

productsCache.Add(product.ProductID, product, CacheItemPriority.Normal, null, new SlidingTime(TimeSpan.FromMinutes(5)));

 

刷新被移除的项

Add方法是你可以指定实现ICacheItemRefreshAction的对象。Refresh方法当项被移出缓存的时候被调用,提供刷新缓存的机会。

下面的代码显示实现ICacheItemRefreshAction接口的类。

 

[Serializable]

  public class ProductCacheRefreshAction : ICacheItemRefreshAction

  {

    public void Refresh(string key, object expiredValue, CacheItemRemovedReason removalReason)

    {

      // Item has been removed from cache. Perform desired actions here, based upon

      // the removal reason (e.g. refresh the cache with the item).

    }

}

 

 

 

 

 

 

 

 

 

 

 

收到项被移除的通知需要你在调用Add方法的时候指定继承ICacheItemRefreshAction接口的类。

 

CacheManager productsCache = CacheFactory.GetCacheManager();

 

string id = "ProductOneId";

string name = "ProductXYName";

int price = 50;

 

Product product = new Product(id, name, price);

 

productsCache.Add(product.ProductID, product, CacheItemPriority.Normal, new ProductCacheRefreshAction(), new SlidingTime(TimeSpan.FromMinutes(5)));

 

使用注意:

加到配置了后端存储的缓存中的项必须是可序列化的。

实现ICacheItemRefreshAction接口的类必须是可序列化的。

 

2.4.2加载缓存

在你使用缓存数据之前,你首先要将数据加载到缓存中。例如,在零售应用中,你可能想加载商品信息到缓存中。

 

目标

在这个场景中,你想通过使用缓存来改变应用程序的性能。

 

解决方案

预先加载:加载所有需要的数据,在整个生命周期内缓存它们。

按需加载:只有当应用请求这段数据时,才加载它,并缓存以备后用。

 

预先方式缓存数据

预先加载的优势

因为可以确保所有的数据已经被加载到缓存中,理论上你不必检查是否在缓存中存在。但因为缓存可能被刷新,所以检查还是必要的。

因为当预先加载时缓存操作被优化,你的应用程序的性能被改善。应用的响应时间也被优化。

 

预先加载的缺点

预先加载并不是最优化的系统,因为缓存中有大量无用的数据。例如,应用包含100个进程,每个进程需要缓存中的一些项。如果只启动这个应用的一个进程,那么上百个缓存项是无用的。

预先缓存将比通常的技术更复杂。在通常的技术中,每一项在一个众所周知的流程中被同步的获取。使用预先缓存需要在多个线程中工作;因此,他很难使其他线程与主线程同步,必须保存线程状态的轨迹,处理异步模型的异常。

 

预先加载的建议

如果你不能正确地预先加载,你的应用将在初始的时候很慢。当你实现预先缓存的时候,你应该使用异步编程模型在后台线程中加载。

在下面的情况下,预先加载被推荐:

l         存储状态是静态或半静态的。如果在其他场景中使用,状态会在使用之前过期。

l         在已知的生存周期中使用状态

l         已知大小的状态。否则可能用尽系统的资源。

l         资源获取很慢。你可以使用这个技术来加载所有的数据。

 

按需加载

按需加载的优势

在初始的时候不加载数据,系统资源不会被滥用。只缓存需要的数据。

 

按需加载的缺点

在第一次请求某个数据的时候,性能很低。你必须检查请求项是否在缓存中。这种检查会经常出现,造成额外的逻辑。

 

按需加载的建议

下面的场景:

l         使用很多的数据,而没有足够可用的资源

l         IO是可靠、稳定、高性能的。

l         在初始时不可用的数据。这些数据可能要根据用户的输入而得。

 

加载的例子

下面是预先加载的例子。从数据源中读取数据,加入缓存。

public List<Product> GetProductList()

{

  // Returns a List filled with Product objects

}

 

public void LoadAllProducts()

{

  List<Product>list = GetProductList();

 

  for (int i = 0; i < list.Count; i++)

  {

    Product product = list[i];

    cache.Add(product.ProductID, product);

}

}

 

 

 

 

下面是按需加载缓存的例子。先检查项是否在缓存中,不存在再获取。

public Product GetProductByID(string anID)

{

  // Returns a Product object with the specified id

}

 

public Product ReadProductByID(string productID)

{

  Product product = (Product)cache.GetData(productID);

 

  // Does our cache already have the requested object?

  if (product == null)

  {

    // Requested object is not cached, so let's retrieve it from

    // data provider and cache it for further requests.

    product = this.dataProvider.GetProductByID(productID);

 

    if (product != null)

    {

      cache.Add(productID, product);

    }

  }

  return product;

}

 

 

2.4.3刷新缓存

刷新使你管理缓存项,确保存储,内存和其他资源被有效的使用。刷新会移除所有缓存中的项,包括那些没有过期的项。例如,在零售应用中,由于用户的选择或用户的登出,使缓存的数据失效。

 

解决方案

CacheManager productsCache = CacheFactory.GetCacheManager();

 

// Operations on the cache

 

productsCache.Flush();

  

2.4.4从缓存中移除项

通过优先级和过期策略,清除和过期过程动态的从缓存中移除项。你也可以指定要移除的缓存。例如,在零售应用中,由用户选择决定哪些数据不再被使用。

 

目标

移除指定的缓存项。

 

解决方案

public void Remove(CacheManager cache, string key)

{

  cache.Remove(key);

}

 

2.4.5从缓存中取数据

缓存中的数据必须被取出才能被使用,例如,零售系统中,你想显示产品的列表。

 

目标

从缓存中获取特定的项。

 

解决方案

// Read the item from the cache. If the item is not found

// in the cache, the return value will be null.

public Product GetProduct(CacheManager cache, string key)

{

  return (Product)cache.GetData(key);

}

 

posted on 2005-12-12 11:54  栖息的熊  阅读(977)  评论(0编辑  收藏  举报

导航