ASP.NET 1.1 Performance Guidelines - Caching
- J.D. Meier, Srinath Vasireddy, Ashish Babbar, John Allen, and Alex Mackman
Separate Dynamic Data from Static Data in Your Pages
Partial page caching enables you to cache parts of a page by using user controls. Use user controls to partition your page. For example, consider the following simple page which contains static, dynamic, and user-specific information.
[main.aspx] <html> <body>
|Application Header – Welcome John Smith
You can partition and cache this page by using the following code:
[main.aspx] <%@ Register TagPrefix="app" TagName="header" src="header.ascx" %> <%@ Register TagPrefix="app" TagName="menu" src="menu.ascx" %> <%@ Register TagPrefix="app" TagName="advertisements" src="advertisements.ascx" %> <%@ Register TagPrefix="app" TagName="footer" src="footer.ascx" %> <html> <body>
|<app:header runat=server />
|<app:menu runat=server />
|<app:advertisements runat=server />
|<app:footer runat=server />
[header.ascx] <%@Control %> Application Header – Welcome <% GetName() %> [menu.ascx] <%@Control %> <%@ OutputCache Duration="30" VaryByParam="none" %> Menu
[advertisements.ascx] <%@Control %> <%@ OutputCache Duration="30" VaryByParam="none" %> Advertisements
[footer.ascx] <%@Control %> <%@ OutputCache Duration="60" VaryByParam="none" %> Footer
By partitioning the content, as shown in the sample, you can cache selected portions of the page to reduce processing and rendering time.
Configure the Memory Limit
When using ASP.NET process model, configure and tune the memory limit using memoryLimit attribute in the <processModel> element of Machine.config file. When using of IIS 6.0 process isolation model configure and tune the memory limit using Memory recycling application pool setting.
ASP.NET trims memory in the cache based on a LRU algorithm and the CacheItemPriority value. If the memory limit is set too high, it is possible for the process to be recycled unexpectedly or your application may experience out-of-memory exceptions. If the memory limit is set too low, it could increase the amount of time spent performing garbage collections, which decreases overall performance.
If the process is being recycled unexpectedly or if your application is giving out-of-memory exceptions, you should consider memory tuning. The default setting is optimized to minimize paging. If you observe high paging activity (by monitoring the Memory\Pages/sec performance counter) you can increase the default limit, provided that your system has sufficient physical memory.
Measure the total memory consumed by the ASP.NET worker process by measuring the Process\Private Bytes (aspnet_wp) performance counter along with paging activity in System Monitor. If the counter indicates that the memory consumption is nearing the default limit set for the process, it might indicate inefficient cleanup in your application. If you have ensured that the memory is efficiently cleaned. Then you will need to increase the memory limit.
ASP.NET Process Model When using the ASP.NET process model, you configure the memory limit in the Machine.config file as follows.
< processModel memoryLimit="60" .../>
This limit is important to adjust when your server has 4 GB or more of RAM. The 60 percent default memory limit means that the worker process is allocated 2.4 GB of RAM, which is larger than the default virtual address space for a process (2 GB). This disparity increases the likelihood of causing an OutOfMemoryException. To avoid this situation in .NET Framework 1.0, you should set the limit to the smaller of 800 MB or 60 percent of physical RAM. .NET Framework 1.1 supports a virtual space of 3 GB. If you put a /3GB switch in boot.ini, you can safely use 1,800 MB as an upper bound for the memory limit.
IIS 6.0 Process Isolation Model When using the IIS 6.0 process isolation model, you can configure the memory limit as follows.
* Open the Internet Information Services (IIS) Manager. * Right click the Application pool. * On the properties, select the Recycling tab. * Unselect the Recycle worker process (in minutes):. * In the Memory recycling section select Maximum used memory (in megabytes) * Set the memory limit to the calculated limit
Note The Memory recycling application pool setting allows you to specify separate limits for physical memory and virtual memory. Physical memory (or a combination of both physical and virtual memory) is commonly used for ASP.NET applications because of the way the common language runtime's garbage collector works. Virtual memory is commonly used for classic native applications that fragment the heap.
An ASP.NET application is deployed on web server having 2 GB RAM. It is configured to use ASP.NET process model. The default memory limit is set to 60% using the memoryLimit attribute of <processModel> element in Machine.config file as follows.
<processModel memoryLimit="60" .../>
Unfortunately the process recycles after the total memory consumed by the process exceeds 60 percent of the physical RAM, in this scenario 1.2 GB. This will cause the process to recycle even in normal load conditions.
An ASP.NET application is deployed on web server having 2 GB RAM. It is configured to use ASP.NET process model. The normal memory consumption of the application process is determined and memoryLimit is configured accordingly.
Monitor the worker process memory by using Process\Private Bytes (aspnet_wp) performance counter. The counter reveals that the process requires 1.3 GB of memory in the normal load conditions.
Since the web server has 2 GB of RAM and the default memoryLimit is 60%, the application process will get recycled when the memory consumption reaches 1.2 GB, in other words the process will be recycled in normal load condition. Set the memoryLimit attribute of the <processModel> element in Machine.config file as follows.
<processModel memoryLimit="70" .../>
With this settings the process will recycles after the total memory consumption exceeds 70 percent of the physical RAM i.e. 1.4 GB. Thus the process will not get recycled in normal load conditions.
- For more information about how to tune the memory limit and about the /3GB switch, see "Configure the Memory Limit" and "/3GB Switch" in Chapter 17, "Tuning .NET Application Performance http://msdn.microsoft.com/library/en-us/dnpag/html/scalenetchapt17.asp
- For more information about running ASP.NET 1.1 with IIS 6, see the Microsoft ASP.NET FAQ page at http://www.asp.net/faq/AspNetAndIIS6.aspx
- For more information about virtual address space and virtual memory paging activities, see Chapter 6, "Evaluating Memory and Cache Usage" in Part 2 of the Windows 2000 Operations Guide at http://www.microsoft.com/resources/documentation/windows/2000/server/reskit/en-us/serverop/part2/sopch06.mspx
- For more information on improving ASP.NET performance see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt06.asp
- For more information about caching architecture see http://msdn.microsoft.com/library/en-us/dnbda/html/CachingArchch2.asp
Determine the Data to be Cached
It is important to cache the right data. If you cache the wrong data, you may adversely affect performance.
Cache application-wide data and data that is used by multiple users. Cache static data and dynamic data that is expensive to create or retrieve. Data that is expensive to retrieve and that is modified on a periodic basis can still provide performance and scalability improvements when managed properly. Caching data even for a few seconds can make a big difference to high volume sites. Datasets or custom classes that use optimized serialization for data binding are also good candidates for caching. If the data is used more often than it is updated, it is also a candidate for caching.
Do not cache expensive resources that are shared, such as database connections, because this creates contention. Avoid storing DataReader objects in the cache because these objects keep the underlying connections open. It is better to pool these resources. Do not cache per-user data that spans requests — use session state for that. If you need to store and to pass request-specific data for the life of the request instead of repeatedly accessing the database for the same request, consider storing the data in the HttpContext.Current.Cache object.
Refresh Your Cache Appropriately
Just because your data updates every ten minutes does not mean that your cache needs to be updated every ten minutes. Determine how frequently you have to update the data to meet your service level agreements. Avoid repopulating caches for data that changes frequently. If your data changes frequently, that data may not be a good candidate for caching.
Cache the Appropriate Form of the Data
If you want to cache rendered output, you should consider using output caching or fragment caching. If the rendered output is used elsewhere in the application, use the cache API to store the rendered output. If you need to manipulate the data, then cache the data by using the cache API. For example, if you need the data to be bound to a combo box, convert the retrieved data to an ArrayList object before you cache it.
Use Output Caching to Cache Relatively Static Pages
If your page is relatively static across multiple user requests, consider using page output caching to cache the entire page for a specified duration. You specify the duration based on the nature of the data on the page. A dynamic page does not always have to be rebuilt for every request just because it is a dynamic page. For example, you might be able to cache Web-based reports that are expensive to generate for a defined period. Caching dynamic pages for even a minute or two can increase performance drastically on high volume pages.
If you need to remove an item from the cache instead of waiting until the item expires, you can use the HttpResponse.RemoveOutputCacheItem method. This method accepts an absolute path to the page that you want to remove as shown in the following code fragment.
The caveat here is that this is specific to a server, because the cache is not shared across a Web farm. Also, it cannot be used from a user control.
Note The next version of ASP.NET (code-named "Whidbey") is likely to support a database cache dependency. If it is implemented, this database cache dependency will allow you to remove items from the cache when data changes in the database.
Choose the Right Cache Location
The @OutputCache directive allows you to determine the cache location of the page by using the Location attribute. The Location attribute provides the following values:
- Any. This is the default value. The output cache can be located on the browser client where the request originated, on a proxy server, or any other server that is participating in the request or on the server where the request is processed.
- Client. The output cache is located on the browser client where the request originated.
- DownStream. The output cache can be stored in any HTTP 1.1 cache-capable device except for the origin server. This includes proxy servers and the client that made the request.
- None. The output cache is disabled for the requested page.
- Server. The output cache is located on the Web server where the request was processed.
- ServerAndClient. The output cache can be stored only at the origin server or at the requesting client. Proxy servers cannot cache the response.
Unless you know for certain that your clients or your proxy server will cache responses, it is best to keep the Location attribute set to Any, Server, or ServerAndClient. Otherwise, if there is not a downstream cache available, the attribute effectively negates the benefits of output caching.
Note The Location attribute does not apply to user controls.
Use VaryBy Attributes for Selective Caching
The VaryBy attributes allow you to cache different versions of the same page. ASP.NET provides four VaryBy attributes:
- VaryByParam. Different versions of the page are stored based on the query string values.
- VaryByHeader. Different versions of the page are stored based on the specified header values.
- VaryByCustom. Different versions of the page are stored based on browser type and major version. Additionally, you can extend output caching by defining custom strings.
- VaryByControl. Different versions of the page are stored based on the property value of a user control. This only applies to user controls.
The VaryBy attribute determines the data that is cached. The following sample shows how to use the VaryBy attribute.
<%@ OutputCache Duration="30" VaryByParam="a" %>
The setting shown in the previous sample would make the following pages have the same cached version:
If you add b to the VaryByParam attribute, you would have three separate versions of the page rather than one version. It is important for you to be aware of the number of variations of the cached page that could be cached. If you have two variables (a and b), and a has 5 different combinations, and b has 10 different combinations, you can calculate the total number of cached pages that could exist by using the following formula:
(MAX a Ã— MAX b) + (MAX a + MAX b) = 65 total variations
When you make the decision to use a VaryBy attribute, make sure that there are a finite number of variations because each variation increases the memory consumption on the Web server.
Use Kernel Caching on Windows Server 2003
Windows Server 2003 and IIS 6.0 provide kernel caching. ASP.NET pages can automatically benefit from the IIS 6.0 kernel cache. Kernel caching produces significant performance gains because requests for cached responses are served without switching to user mode.