Enterprise Library Caching Application Block Brian Button Software Design Engineer Ron Jacobs Product Manager Scott Densmore Software Design Engineer Agenda Caching architectural guidance from patterns & practices Describe implementation of caching scenarios and guidance using the Caching Application Block Demonstration Questions Sound familiar? Users are complaining about application performance You have already spent the next year’s IT budget scaling out your database servers to handle the amount of requests for data Your application cannot perform, or is severely degraded, without a live connection to the backend data source Why Cache? Performance Storing relevant data as close as possible to the data consumer avoids repetitive data creation, processing, and transportation Scalability Avoid wasting resources processing the same data, business functionality, and user interface fragments required by multiple users and processes Reduce database requests, allowing more users to be served Availability Storing that data in another place, your application may be able to survive system failures such as network latency, Web service problems, or hardware failures Sample Application Caching Scenarios You are creating a smart client application that uses locally cached reference data to create requests and support offline operations You are creating a Windows Service or Console application which needs a cache to improve performance Caching Application Block Provides a flexible and extensible caching mechanism that can be used at all layers of an application Supports backing stores that persist cache data into a database or isolated storage, so the data can survive app restarts Easy to use Easy to configure, using the Enterprise Library Configuration Tool Thread-safe Ensures that the states of the in-memory cache and the backing store remain synchronized. Exploring the Caching Application Block Creating the Caching Application Block configuration Selecting a backing store Creating the cache Adding an item to the cache Setting the expiration policy Retrieving an item from the cache Implementing cache loading strategies Removing an item from the cache Flushing the cache Key extensibility points Creating Configuration Add the Caching Application Block to your application configuration Create a cache manager for each set of data to be cached Designate one as the default cache manager Cache Storage Guidance Memory resident cache. Memory-based caching is usually used when: An application is frequently using the same data An application often needs to reacquire the data Disk resident cache. Disk based caching is useful when: You are handling large amounts of data Data in the application services (for example, a database) may not always be available for reacquisition (for example, in offline scenarios) Cached data lifetime must survive process recycles and computer reboots Caching Architecture Guide for .NET Framework Applications Caching Application Block Storage Cache always exists in memory Cache always has a backing store Null backing store (in-memory only, not persistent) Persistent storage Persistent backing stores Useful when cached data lifetime must survive process recycles and computer reboots Isolated storage, Data Access Application Block Contents always match in-memory cache In-memory cache is loaded from backing store during cache initialization Backing Store Configuration Isolated Storage Segregated by user and assembly Caching Application Block provides partition to segregate multiple cache managers within an application Backing Store Configuration Data Access Application Block Segregated by database instance and named partition Require configuring the Data Access Application Block Backing Store Configuration Encrypting cache data in the backing store Requires Cryptography Application Block Select Symmetric provider to use Creating the Cache in Code Create the default cache manager CacheManager myCache = CacheManager.GetCacheManager(); Create the cache manager named “Products” CacheManager productsCache = CacheManager.GetCacheManager(“Products”); Adding an Item to the Cache Add an item to the cache with defaults productsCache.Add(“ProductID123”, productObject); Defaults Scavenging priority: Normal No expiration Notes Adding a second item with the same key as an existing item replaces the existing item When configured to use a persistent backing store, objects added to the cache must be serializable Determining an Expiration Policy Time-based expirations Invalidate data based on either relative or absolute time periods For use when volatile cache items—such as those that have regular data refreshes or those that are valid for only a set amount of time—are stored in a cache. Notification-based expirations Validity of a cached item based on the properties of an application resource, such as a file, a folder, or any other type of data source. Time-Based Expirations Absolute. Allows you to define the lifetime of an item by specifying the absolute time for an item to expire. Simple—You define the lifetime of an item by setting a specific date and time for the item to expire. Extended—You define the lifetime of an item by specifying expressions such as every minute, every Sunday, expire at 5:15 AM on the 15th of every month, and so on. Sliding. Allows you to define the lifetime of an item by specifying the interval between the item being accessed and the policy defining it as expired. Time-Based Expirations Requires using extended overload of Add method Caching Application Block classes support timebased expirations AbsoluteTime SlidingTime ExtendedFormatTime Absolute time example: expire at 2:00 AM on 3/21/05 DateTime refreshTime = new DateTime(2005, 3, 21, 2, 0, 0); AbsoluteTime expireTime = new AbsoluteTime(refreshTime); primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal, null, expireTime); Sliding Time Expirations Sliding time example: expire if item has not been accessed for 5 minutes TimeSpan refreshTime = new TimeSpan(0, 5, 0); SlidingTime expireTime = new SlidingTime(refreshTime); primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal, null, expireTime); Extended Time Format Expirations Extended time format “<Minute> <Hour> <Day of month> <Month> <Day of week>” * means run every period Examples “* * * * *” “5 * * * *” “* 21 * * *” every day “31 15 * * *” “7 4 * * 6” “15 21 4 7 *” expires every minute expire 5th minute of every hour expire every minute of the 21st hour of expire 3:31 PM every day expire Saturday 4:07 AM expire 9:15 PM on 4 July Extended Time Format Expirations Extended format example: expire at midnight every Saturday ExtendedFormatTime expireTime = new ExtendedFormatTime("0 0 * * 6"); primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal, null, expireTime); Notification-Based Expirations File dependency example: expire if the file Trigger.txt is changed FileDependency expireNotice = new FileDependency(“Trigger.txt”); productsCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal, null, expireNotice); You can create custom expirations by creating classes that implement ICacheItemExpiration Configuring Expiration Poll Frequency Removal of expired items occurs on a background thread You can set the frequency of how often this thread will run looking for expired items Item Removal Notifications Caching Application Block provides notification when an item is removed from cache Item has expired Item was removed explicitly through code Item was scavenged Provide an object that implements ICacheItemRefreshAction when item is added to cache productsCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal, new ProductCacheRefreshAction(), expireNotice); Item Removal Notifications Class implementing ICacheItemRefreshAction must be marked as Serializable (for persistent backing store) [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). } } Retrieving an Item from the Cache Cast returned object to correct type Check for null (item not found in cache) public Product ReadProductByID(string productID) { Product product = (Product)cache.GetData(productID); if (product == null) { // Item not in cache } } Loading the Cache Proactive loading Cache is preloaded with items on application startup Application response time improves, as all items are in cache Application startup time increases, as all items are loaded May cache items that are never requested, using unnecessary resources Loading typically done on a separate thread, increasing complexity Reactive loading Cache an item after it is retrieved from the data source Only caches items truly needed (uses less resources) Response times slower during application execution if an item is not yet cached Loading the Cache Proactively Create cache manager CacheManager productsCache = CacheManager.GetCacheManager(); Add items during component initialization // Retrieve the data from the source ArrayList list = dataProvider.GetProductList(); // Add all the items to the cache for (int i = 0; i < list.Count; i++) { Product product = (Product) list[i]; productsCache.Add( product.ProductID, product ); } Loading the Cache Reactively Create cache manager CacheManager productsCache = CacheManager.GetCacheManager(); Add items when retrieved from data source Product product = (Product) productsCache.GetData(productID); if (product == null) { // Retrieve it from the data provider // and cache it for more requests. product = dataProvider.GetProductByID(productID); if (product != null) { productsCache.Add(productID, product); } } Loading the Cache Proactive caching is recommended in situations that have one or more of the following characteristics: You are using static or semistatic state that has known update periods. If you use it in other scenarios, the state might expire before it is used. You are using state with a known lifetime. You are using state of a known size. If you use proactive cache data loading when you do not know the size of the data, you might exhaust system resources. You must try to not use resources that you do not have. You have problematic resources, such as a slow database, a slow network, or unreliable Web services. You can use this technique to retrieve all the state proactively, cache it, and work against the cache as much as it can. Loading the Cache Reactive caching is recommended in situations that have one or more of the following characteristics: You are using lots of state and you do not have sufficient resources to cache all state for the entire application. You are using reliable and responsive resources, such as a database, network, or Web service that will not impede application stability and performance. You are interested in caching data that is not available during the initialization of an application. For example, this data might be affected by user input such as common search queries or user-specific data such as a user's profile. Removing an Item from the Cache Remove item with specified key productsCache.Remove(“Product101Key”) No error occurs if key is not found Flushing the Cache Use to manage storage, memory and other resources efficiently Explicit flushing Initiated by application code Removes all items from the cache productsCache.Flush() Scavenging Initiated by application block Based upon priority and last access time Configuration settings control size of cache and number removed Flushing the Cache with Scavenging Scavenging configuration Maximum elements in cache Number of items removed when scavenging occurs Flushing the Cache with Scavenging Priority is established when an item is added to the cache productsCache.Add("Key1", "Cache Item1", CacheItemPriority.High, new ProductCacheRefreshAction(), expireNotice) Priority values Low Normal High NotRemovable The scavenging algorithm is not an extension point View/Application Share: Demonstration [Live Meeting View/Application Share. Use Live Meeting > Edit Slide Properties... to edit.] Key Extensibility Points Custom backing store provider Implement IBackingStore (derive from BaseBackingStore) Use Configuration Console to select custom provider Custom expiration policy Implement ICacheItemExpiration Specify object on call to Add method of CacheManager object Plus… Anything and everything – you have the source code! Please post extensions and suggestions to the community Enterprise Library v1 Caching Exceptions Legend Security Data Access Logging Dependency Plug-in Crypto Configuration Config Tool Announcing: Enterprise Library 1.0 http://www.microsoft.com/practices patterns & practices Live! 3/14 Enterprise Library Logging & Instrumentation Application Block 3/17 Enterprise Library Exception Handling Application Block 3/22 Enterprise Library Cryptography Application Block 3/24 Enterprise Library Security Application Block http://www.pnplive.com http://www.microsoft.com/practices Enterprise Library Community http://go.microsoft.com/fwlink/?linkid=39209&clcid=0x09