Top 10 Ways to Improve ASP.Net Application Performance
Author:Eve Cole
Update Time:2009-06-30 15:49:49
This article discusses:
Commonly told myths about improving asp.net application performance Useful tips to improve asp.net application performance
Recommendations for operating databases with Asp.net applications
Caching and background processing in Asp.net
Nowadays, writing an ASP.NET web application has become very simple, and many programmers are unwilling to spend time building an application with good performance. This article will discuss the top ten ways to improve the performance of web applications. I won't limit my discussion to just ASP.NET applications as they are only a subset of web applications. This article also cannot provide a complete guide to improving web application performance, as that would require the length of a book. This article only provides a good starting point for improving web application performance. (The only thing left is to study slowly by ourselves).
Outside of work, I often go rock climbing. Before each rock climbing, I will review the rock climbing route map and read the advice of previous successful rock climbers. Because we need their successful experience. Similarly, when you need to modify a program with performance problems or develop a high-performance website, you also need to learn how to write a high-performance web application.
My personal experience mainly comes from working as a program manager in Microsoft's asp.net group, running and managing the www.asp.net website, and assisting in the development of Community Server (which is an integrated and upgraded version of asp.net Forums, .Text, and nGallery software). I think these experiences can help me.
You might think of dividing your application into different logical layers. You may also have heard of three-tier physical architecture or N-tier architecture, which is the most commonly used architecture model. It physically assigns different program functions to various hardware for execution. In this way, if we want to improve the performance of the application, adding some hardware can achieve the goal. It stands to reason that this method can improve the performance of the application, but we should avoid using this method. Therefore, whenever possible, we should put the ASP.NET page and the components it uses into an application.
Because of distributed deployment and the use of web services or remoting, it will reduce the performance of the application by 20% or more.
The data layer is a little different. It's better to deploy it independently and use a separate hardware to run it. Despite this, the database is still the bottleneck of application performance. Therefore, when you want to optimize your program, the first place that comes to mind should be optimizing the data layer.
Before you modify an area of your application that is causing performance problems, you'll want to make sure that the program that's causing the problem looks tight. Performance profilers are very useful for finding where in your application it's taking how long. These are places that we cannot feel intuitively.
This article discusses two types of performance optimizations: one is big performance optimizations (big optimizations), such as using asp.net's Cache; the other is small performance optimizations (tiny optimizations). Small performance optimizations can sometimes be very useful. You make a small change to your code and call it a thousand or ten thousand times at a time. Make a big performance optimization and you'll see a big improvement in the speed of your application. A small performance optimization may only improve one microsecond per request, but if the number of requests per day is large, the application will have a significant performance improvement.
Data layer performance
When you want to optimize the performance of an application, you can work in the following order: Does your code need to access the database? If so, how often should the database be accessed? Likewise, this testing method can also be used in program code that uses web services or remoting. This article will not discuss the issue of program optimization using Web services and Remoting.
If there is a request in your code that must access the database, and you see code that implements the same function elsewhere, then you need to optimize it first. Modify and improve and continue testing. Unless you have a very large performance problem, your time is better spent on optimizing queries, connecting to the database, returning the size of the data set, and the time it takes to return a query.
Based on the summary of experience, let's take a look at ten experiences that can help you improve the performance of your application. I will explain them in order from the largest to the smallest in terms of how much they improve efficiency.
1. Return multiple data sets
Check your database access code to see if there are any requests that return multiple times. Each round trip reduces the number of requests per second your application can respond to. By returning multiple result sets in a single database request, you reduce the time it takes to communicate with the database, make your system scalable, and reduce the workload on the database server to respond to requests.
If you are using dynamic SQL statements to return multiple data sets, then I recommend that you use stored procedures instead of dynamic SQL statements. Whether to write business logic into stored procedures is a bit controversial. But I think that writing business logic into stored procedures can limit the size of the returned result set, reduce network data traffic, and eliminate the need to filter data at the logic layer. This is a good thing.
Use the ExecuteReader method of the SqlCommand object to return a strongly typed business object, and then call the NextResult method to move the data set pointer to locate the data set. Example 1 demonstrates an example of returning multiple ArrayList strongly typed objects. Returning only the data you need from the database can greatly reduce the memory consumption of your server.
2. Paging the data
ASP. NET's DataGrid has a very useful feature: paging. If the DataGrid allows paging, it will only download the data of a certain page at a certain time. In addition, it has a navigation bar for data paging, which allows you to choose to browse a certain page, and only download one page of data at a time. .
But it has a small disadvantage, that is, you must bind all data to the DataGrid. In other words, your data layer must return all the data, and then the DataGrid filters out the data required by the current page and displays it. If there is a result set of 10,000 records that needs to be paginated using the DataGrid, assuming that the DataGrid only displays 25 pieces of data per page, it means that 9975 pieces of data will be discarded in each request. Each request must return such a large data set, which has a huge impact on the performance of the application.
A good solution is to write a paging stored procedure. Example 2 is a paging stored procedure for the orders table of the Northwind database. You only need to pass in the current page number and the number of items displayed on each page, and the stored procedure will return the corresponding results.
On the server side, I specially wrote a paging control to handle the paging of data. Here, I used the first method and returned two result sets in a stored procedure: the total number of data records and the required result set.
The total number of records returned depends on the query being executed; for example, a where condition can limit the size of the result set returned. Because the total number of pages must be calculated based on the size of the data set records in the paging interface, the number of records in the result set must be returned. For example, if there are 1,000,000 records in total, if you use the where condition, you can filter to only return 1,000 records. The paging logic of the stored procedure should know to return the data that needs to be displayed.
3. Connection pool
Using TCP to connect your application to the database is expensive (and time-consuming). Microsoft developers can use connection pools to reuse database connections. Rather than using TCP to connect to the database for each request, the connection pool only creates a new TCP connection when there is no valid connection. When a connection is closed, it will be placed in the pool and it will still maintain a connection to the database, thus reducing the number of TCP connections to the database.
Of course, you should pay attention to those connections that you forgot to close. You should close it immediately after each use. What I want to emphasize is: No matter what anyone says, the GC (garbage collector) in the .net framework will always call the Close or Dispose method of the connection object to explicitly close your connection after you have finished using the connection object. Don't expect the CLR to close the connection within the time you imagine. Although the CLR will eventually destroy the object and close the connection, we are not sure when it will do these things.
To use connection pool optimization, there are two rules. First, open the connection, process the data, and then close the connection. If you have to open or close the connection multiple times per request, it's better than opening a side connection all the time and passing it to each method. Second, use the same connection string (or the same user ID, when you use integrated authentication). If you are not using the same connection string, for example if you are using a connection string based on the logged in user, this will not take advantage of the optimization features of the connection pool. If you are using integrated arguments, you cannot take full advantage of the optimization function of the connection pool because there are many users. .NET CLR provides a data performance counter, which is very useful when we need to track program performance characteristics, including connection pool tracking.
Whenever your application connects to a resource on another machine, such as a database, you should focus on optimizing the time it takes you to connect to the resource, the time it takes to receive and send data, and the number of times you go back. Optimizing every process hop in your application is the starting point for improving the performance of your application.
The application layer contains the logic to connect to the data layer, transfer data to instances of the corresponding classes, and business processing. For example, in Community Server, you need to assemble a Forums or Threads collection, and then apply business logic, such as authorization. More importantly, you need to complete the caching logic here.
4. ASP. NET cache API
Before writing an application, the first thing you need to do is to make the application maximize the use of ASP.NET's caching capabilities.
If your component is to be run in an Asp.net application, you only need to reference System.Web.dll into your project. Then use the HttpRuntime.Cache property to access the Cache (it can also be accessed through Page.Cache or HttpContext.Cache).
There are several rules for caching data. First, the data may be used frequently and this data can be cached. Second, the access frequency of data is very high, or the access frequency of a piece of data is not high, but its life cycle is very long. It is best to cache such data. The third is a problem that is often ignored. Sometimes we cache too much data. Usually on an X86 machine, if the data you want to cache exceeds 800M, a memory overflow error will occur. So the cache is limited. In other words, you should estimate the size of the cache set and limit the size of the cache set to less than 10, otherwise it may cause problems. In Asp.net, if the cache is too large, a memory overflow error will be reported, especially if a large DataSet object is cached.
Here are a few important caching mechanisms that you must understand. First, the cache implements the "most recently used" principle (a least-recently-used algorithm). When there are few caches, it will automatically forcefully clear useless caches. Secondly, the principle of "conditional dependencies" forced elimination (expiration dependencies), the conditions can be time, keywords and files. Time as a condition is the most commonly used. A stronger condition is added in asp.net2.0, which is the database condition. When the data in the database changes, the cache is forced to be cleared. For a more in-depth look at database conditional dependencies, see Dino Esposito's Cutting Edge column in the July 2004 issue of MSDN Magazine. The cache architecture of Asp.net is shown in the figure below:
5. Pre-request caching
Earlier, I mentioned that even if we only make a small performance improvement in some places, we can get a big performance improvement. I really like using pre-request caching to improve the performance of the program.
Although the Cache API is designed to save data for a certain period of time, the pre-request cache only saves the content of a certain request for a certain period of time. If the access frequency of a certain request is high, and this request only needs to extract, apply, modify or update the data once. Then the request can be pre-cached. Let's give an example to illustrate.
In the CS forum application, the server control of each page requires customized data to determine its skin, to determine which style sheet to use and other personalized things. Some of the data here may need to be saved for a long time, but some times may not. For example, the skin data of a control only needs to be applied once and can be used all the time.
To implement pre-request caching, use Asp.net's HttpContext class. An instance of the HttpContext class is created on every request and can be accessed through the HttpContext.Current property anywhere during the request. The HttpContext class has an Items collection property, and all objects and data are added to this collection and cached during the request. Just like you use Cache to cache frequently accessed data, you can use HttpContext.Items to cache basic data that is used in each request. The logic behind it is simple: we add a data to HttpContext.Items, and then read the data from it.
6. Background processing
With the above method your application should run very fast, right? But at some point, a very time-consuming task may be performed in a request in the program. Such as sending emails or checking the correctness of submitted data, etc.
When we integrated asp.net Forums 1.0 into CS, we found that submitting a new post would be very slow. Every time a new post is added, the application must first check whether the post is a duplicate, then filter it using the "badword" filter, check the image attachment code, index the post, and add it to the appropriate queue. , validate its attachment, and finally, send the email to its subscriber's mailbox. Obviously, this is a lot of work.
The result is that it spends a lot of time indexing and sending emails. Indexing posts is a time-consuming operation, and sending emails to subscribers requires connecting to the SMTP service and then sending an email to each subscriber. As the number of subscribers increases, the time it takes to send emails will increase. long.
Indexing and sending emails do not need to be triggered on every request. Ideally, we would like to process these operations in batches, sending only 25 emails at a time or all new emails to be sent every 5 minutes. We decided to use the same code as the database prototype cache, but it failed, so we had to go back to VS.NET 2005.
We find the Timer class under the System.Threading namespace. This class is very useful, but few people know it, and even fewer web developers know it. Once he creates an instance of this class, the Timer class will call the specified callback function from a thread in the thread pool every specified time. This means your ASP.NET application can run even when there are no requests. This is the solution to be dealt with later. You can have the indexing and emailing work run in the background instead of having to execute it on every request.
There are two problems with the background running technology. The first is that when your application domain is uninstalled, the Timer class instance will stop running. That is, the callback method will not be called. In addition, because there are many threads running in each process of the CLR, it will be difficult for you to get a thread for Timer to execute it, or it will be able to execute it, but it will be delayed. The Asp.net layer should use this technique as little as possible to reduce the number of threads in the process, or only allow requests to use a small part of the threads. Of course, you can only use it if you have a lot of asynchronous work.
There is not enough space to post the code here. You can download the sample program from http://www.rob-howard.net/ . Please download the Blackbelt TechEd 2004 sample program.
7. Page output caching and proxy services
Asp.net is your interface layer (or should be), it contains pages, user controls, server controls (HttpHandlers and HttpModules) and the content they generate. If you have an Asp.net page that outputs html, xml, imgae or other data, and you use code to generate the same output content for each request, it is necessary for you to consider using page output caching.
You can do this by simply copying the following line of code into your page:
<%@ PageOutputCache VaryByParams=”none” Duration=”60” %>
You can effectively use the page generated in the first request to output the cached content, and regenerate the page content after 60 seconds. This technology is actually implemented using some low-level Cache API. There are several parameters that can be configured for page output caching, such as the VaryByParams parameter mentioned above. This parameter indicates when to trigger re-output conditions. You can also specify to cache output in Http Get or Http Post request mode. For example, when we set this parameter to VaryByParams="Report", the output requested by default.aspx?Report=1 or default.aspx?Report=2 will be cached. The value of a parameter can be multiple parameters separated by semicolons.
Many people don't realize that when using page output caching, ASP.NET will also generate an HTTP header set (HTTP Header) and save it in the downstream cache server. This information can be used for Microsoft Internet security and to speed up the server's response. speed. When the HTTP cache header is reset, the requested content will be cached in the network resource. When the client requests the content again, it will no longer obtain the content from the origin server, but directly obtain the content from the cache.
Although using page output caching does not improve the performance of your application, it does reduce the number of times cached page content is loaded from the server. Of course, this is limited to caching pages accessible to anonymous users. Because once the page is cached, authorization operations can no longer be performed.
8. Use Kernel Caching of IIS6.0
If your application is not running in IIS 6.0 (Windows Server 2003), then you have lost some great ways to improve application performance. In the seventh method, I talked about how to use page output caching to improve application performance. In IIS5.0, when a request comes to IIS, IIS will transfer it to asp.net. When the page output cache is applied, the HttpHandler in ASP.NET will receive the request, and the HttpHandler will transfer the content from the cache. Take it out and return it.
If you are using IIS6.0, it has a very good feature called Kernel Caching, and you do not have to modify any code in the asp.net program. When asp.net receives a cached request, IIS's Kernel Cache will get a copy of it from the cache. When a request comes from the network, the Kernel layer will get the request. If the request is cached, it will directly return the cached data, and you are done. This means that when you use IIS Kernel Caching to cache page output, you will get incredible performance improvements. When developing asp.net for VS.NET 2005, I was a program manager specifically responsible for asp.net performance. My programmers used this method. I looked at all the daily report data and found the results of using kernel model caching. Always the fastest. A common feature of them is that the network requests and responses are large, but IIS only takes up 5% of the CPU resources. This is amazing. There are many reasons for you to use IIS 6.0, but kernel cashing is the best one.
9. Compress data with Gzip
Unless your CPU usage is too high, it is necessary to use techniques to improve server performance. Using gzip to compress data can reduce the amount of data you send to the server, improve the running speed of the page, and also reduce network traffic. How to compress the data better depends on the data you want to send, and whether the client's browser supports it (IIS sends gzip-compressed data to the client, and the client must support gzip to parse it, IE6.0 and Firefox). In this way, your server can respond to more requests per second. Similarly, you also reduce the amount of data sent in the response, and you can send more requests.
Good news, gzip compression has been integrated in IIS6.0, it is better than gzip in IIS5.0. Unfortunately, to enable gzip compression in IIS 6.0, you cannot set it in the properties dialog of IIS 6.0. The IIS development team developed the gzip compression function, but they forgot to make it easy for administrators to enable it in the administrator window. To enable gzip compression, you can only modify its configuration in the IIS6.0 xml configuration file.
In addition to reading this article, I have to read the article <<IIS6 Compression>> written by Brad Wilson ( http://www.dotnetdevs.com/articles/IIS6compression.aspx ); there is also an article introducing the basic knowledge of aspx compression. Enable ASPX Compression in IIS. But be aware that dynamic compression and kernel cashing are mutually exclusive in IIS6.
10. ViewState of server controls
ViewState is a feature in asp.net that is used to save a state value used to generate a page in a hidden field. When the page is posted back to the server, the server parses, verifies, and applies the data in ViewState to restore the page's control tree. ViewState is a very useful feature that can persist client state without using cookies or server memory. Most server controls use ViewState to persist the state values of elements that interact with the user on the page. For example, to save the page number of the current page for paging.
Using ViewState will bring some negative effects. First, it increases the server's response and request times. Secondly, each postback adds time to serialize and deserialize data. Finally, it also consumes more memory on the server.
Many server controls tend to use ViewState, such as the well-known DataGrid, and sometimes there is no need to use it. ViewState is enabled by default. If you don't want to use ViewState, you can turn it off at the control or page level. In the control, you only need to set the EnableViewState property to False; you can also set it in the page to extend its scope to the entire page:
<%@ Page EnableViewState=”false” %>
If the page does not require a postback or the page is just rendered with controls each time it is requested. You should turn off ViewState at the page level.
Summarize
I just provide a few tips that I think will help improve writing high-performance ASP.NET applications. The tips for improving ASP.NET performance mentioned in this article are just a starting point. For more information, please refer to "Improving ASP.NET" Performance" book. Only through your own practice can you find the techniques that will be most helpful for your project. However, these tips can serve as a guide on your development journey. In software development, none of these are absolutely useful because every project is different.