How To: Design Caching for Web Application
J.D. Meier, Alex Homer, David Hill,
Jason Taylor, Prashant Bansode, Lonnie Wall, Rob Boucher Jr, Akshay Bogawat
- Learn how to decide what it is appropriate to cache.
- Learn how to decide where you should cache data.
- Learn how to decide the appropriate format for the cached data.
- Learn effective caching strategies.
- Learn the caching anti-patterns.
- Learn manageability, performance, and security considerations for caching.
Summary of Steps
- Step 1 – Determine the Data to Cache.
- Step 2 – Determine Where to Cache Data.
- Step 3 – Determine the Format of Your Data to Cache.
- Step 4 – Determine a Suitable Cache Management Strategy.
- Step 5 – Determine How to Load the Cache Data.
Step 1 – Determine the Data to Cache
It is important to determine, as part of your application design, the data that can be cached. Create a list of the data to cache in each layer of your application. Consider caching the following types of data.
- Application Wide Data – Consider caching relatively static data that applies to all users of the application. Examples are product lists and product information.
- Relatively Static Data – Consider caching data that is fully static, or which does not change frequently.
- Relatively Static Web pages – Consider caching the output of pages that do not change frequently.
- Stored procedure parameters and query results – Consider caching frequently used query parameters and query results.
Step 2 – Determine Where to Cache Data
When deciding on where to cache, there are typically two things you must consider: the physical location of the cache, and the logical location of the cache.
Determine the Physical Location of the Cache
The various options available for physical location of caching implementation options can be categorized as in-memory cache or disk cache.
An in-memory cache is a good choice when:
- The data is used frequently by the application.
- The cached data is relatively volatile and must be frequently re-acquired.
- The volume of cached data is relatively small.
Storing your cache on the file-system or in a database is a good choice when:
Determine the Logical Location of the Cache
- Accessing data from cache store is efficient as compared to acquiring the data from the original store.
- The cached data is relatively less volatile, and the services for requiring the data are not always available.
- The volume of cached data is relatively large.
- The cached data must survive process and machine restarts.
It is important to cache the data as close as possible to the location where it will be used, which reduces processing and network round trips and improves the performance and responsiveness of the application. Consider the following guidelines when deciding
on the logical location of the cache data.
Caching data on the client side is a good choice when:
- The cached data is page-specific or user-specific.
- The cached data does not contain sensitive information.
- The cached data is lightweight.
Typically, you will cache page output on a proxy server to avoid frequently processing the same page or results. Caching on proxy server is a good choice when:
- You have relatively static pages that are requested frequently by clients.
- Your pages are updated with a known frequency.
- You have pages that can generate different output based on HTTP parameters, and those outputs do not often change. This is particularly useful when the range of outputs is small.
- Results are returned from Web services.
Caching data in the presentation layer is a good choice when:
- You have relatively static page outputs.
- You have very little data related to user preferences and user data for a small set of users.
- You have data that must be displayed to the user, and is expensive to create. For example, you can cache data such as product lists and product information.
- You have UI controls that are expensive to create.
Caching data in the business layer is a good choice when:
- You must maintain state for a service.
- You must maintain state for a business process.
- You must maintain state for a workflow.
- Relatively static data is required to process requests from the presentation layer, and this data is expensive to create.
Caching data in the data access layer is a good choice when:
- You have input parameters in a collection that are used for a frequently called stored procedure.
- You have small volumes of raw data that are returned from frequently executed queries.
- You have schemas for typed datasets.
Caching in a database is a good choice when:
- You have data that requires considerable query processing to obtain the result set.
- You have too large a volume of data to cache in the application layers. Implementing a paging mechanism can increase performance in this case.
Step 3 – Determine the Format of Your Data to Cache
After you have determined the data that you must cache, and where to cache it, the next important task is to identify the format for the cached data. The following key considerations will help you to decide the format of the data to be cached.
When you are caching data, store it in a normalized format that is optimized for the intended use, so that it does not require additional processing or transformation. Normalized cached data is a good choice when:
- You must cache data using an in-memory cache.
- You do not need to share the cache across processes or computers.
- You do not need to transport cached data between memory locations.
- You need to cache raw data such as DataSets, DataTables, , and Web pages.
If you need to store or transport the cached data, consider serializing requirements. Serializing the cached data is a good choice when:
- You need to cache data in a disk cache.
- You need to store session state on a separate server or in a SQL Server database.
- You need to share the cache across process or computers.
- You need to transport the cached data between memory locations.
- You need to cache custom objects.
You can choose to serialize your data with an XML serializer or a binary serializer. An XML serializer is a good choice when interoperability is your key concern. If performance is your key concern, then consider using a binary serializer.
Step 4 – Determine a Suitable Cache Management Strategy
Your cache management strategy involves determining an appropriate cache expiration and cache flushing policy. Expiration and flushing are related to the removal of cached data from the cache store. The difference is that flushing might remove valid cache items
to make space for more frequently used items, whereas expiration removes invalid and expired items.
Design a cache expiration strategy that will maintain the validity of the data and items in the cache. When deciding on the cache expiration policy, consider both time-based expiration and notification-based expiration.
Using a time-based expiration policy, the cached data is expired or invalidated based on relative or absolute time intervals. This is a good choice when:
- The cache data is volatile.
- The cached data is regularly updated.
- The cached data is valid for only specific time period or interval.
When choosing a time-based expiration policy, you can choose an absolute time expiration policy or a sliding time expiration policy. An absolute expiration policy allows you to define the lifetime of cached data by specifying the absolute time at which it will
expire. A sliding time expiration policy allows you to define the lifetime of cached data by specifying the interval between the last access and the time at which it will expire.
Using a notification-based expiration policy, the cached data is expired or invalidated based on notifications from internal or external sources. This is a good choice when:
- You are working with non-volatile cache data.
- The cached data is updated are at irregular intervals.
- The data is valid unless changed by external or internal systems.
The common sources of notifications are disk file writes, WMI events, and business logic operations. Whenever a notification-linked file is changed, WMI event raised, or business operation executed, the corresponding cache data is expired or invalidated. In
some scenarios, you may want to have cache expiration depend on an external source such as a database or other system. In this case, you can usually subscribe to specific event of the external system and expire or invalidate the cache when the event occurs.
Design a cache flushing strategy so that storage, memory, and other resources are used efficiently. When deciding on the cache flushing strategy you can choose explicit flushing or scavenging.
Explicit flushing requires you to determine when an item should be flushed and then remove it. This is good choice when:
- You must support the scenario of removing damaged or obsolete cached data.
- You are working with custom stores that do not support scavenging.
- You are working with a disk-based cache.
requires you to determine the conditions and heuristics in which an item should be scavenged. This is good choice when:
- You want to activate scavenging automatically when system resources become scarce.
- You want to remove seldom-used or unimportant items from the cache automatically.
- You are working with a memory-based cache
Common scavenging heuristics include:
- The Least Recently Used Algorithm scanvenges the items that have not been used for the longest period of time.
- The Least Frequently Used Algorithm scanvenges the items that have been used least frequently since they were loaded.
- The Priority Algorithm instructs the cache to assign a priority to certain items and attempt to keep these when it scavenges the cache.
Step 5 – Determine How to Load the Cache Data
This section walks you through the options available for populating the cache. Choosing the appropriate option helps to improve the performance and responsiveness of your application. When determining how to populate the cache, consider how much of the data
you want to be available when the application starts or when you initially load the cache. For example, you may decide to load data into the cache when the application initializes, or to acquire the data only when it is requested.
You can use either proactive or reactive loading when designing your cache population strategy. If you choose proactive loading, you will retrieve the required data for the application when it starts and then cache it for the lifetime. If you choose reactive
loading, you will retrieve data as it is requested by the application and cache it for future requests.
Proactive loading is a good choice:
- If your cached data is relatively static or has a known update frequency.
- If your cached data has a known lifetime.
- If your cached data has a known size. If you do not know the size of the data, you might exhaust system resources loading it all.
- If the source for your cached data is a slow database or data is retrieved across a slow network or from an unreliable Web service.
Reactive loading is a good choice:
- If your cached data is relatively volatile.
- If you are not sure of your cache data lifetime.
- If your cached data volume is large.
- If your cache data source is reliable and responsive.