10 tips for writing a high-performance Web application

Source: Internet
Author: User
Tags configuration settings connection pooling http post rowcount knowledge base

This article discusses:

• General Video Tutorial ' >asp. NET performance of the Secret

• Useful tips and tricks to improve the performance of ASP.

• Recommendations for using databases in ASP.

· Asp. NET cache and background processing

It's incredibly easy to write a Web application using ASP. It's so easy that many developers don't spend time building their apps to do a good job. In this article, I'll recommend 10 tips for writing high-performance Web applications. I'm not going to talk about me. The discussion is limited to the ASP. NET application because the ASP. NET application is just a subset of the Web application. This article will not be an authoritative guide to optimizing the performance of Web applications-a complete book can be easily done. Instead, we should take this article as a good starting point.

Before I became a workaholic, I would go to rock climbing a lot. Before doing any rock climbing, I'd prefer to take a look at the route in the guidebook and read the recommendations made by those who have been to the summit. However, no matter how well the guidebook is written, you will need to have actual rock climbing experience before trying a challenging goal. Similarly, you can only learn how to write high-performance WEB applications when you are faced with problems repairing performance problems or running a high-throughput site.

My personal experience comes from the experience of being a basic program manager in the Microsoft's ASP. NET team, maintaining and managing www.asp.net, and helping to architect community Server, which is a few well-known ASP. NET Forums applications. Text, and the next version of Ngallery connected to a platform). I believe that some of the techniques that have helped me will also be useful to you.

You should consider separating your application into several logical layers. You may have heard of the 3-tier (or N-tier) architecture. These are often defined structural patterns that physically divide the business and/or hardware from one function to the other. If the system needs a larger scale, more hardware can be easily added. However, that would result in a performance degradation associated with business and machine jumps, so we should avoid it. So whenever possible, try to run ASP. NET pages and related components of the page in the same application.

Because of the separation of code and the boundaries between hierarchies, using Web services or remoting can degrade performance by 20% or more.

The data layer is a bit different because it is usually preferable to have hardware that is dedicated to the database. However, the cost of a process jumping to a database is still high, so the performance at the data layer is the first thing you should consider when optimizing your code.

Before you invest in repairing the performance problems of your application, make sure that you analyze your application to discover the root cause of the problem. A key performance counter, such as a counter that indicates the percentage of time spent in the garbage collection process, is also useful to find out where the application has spent the primary time. While the places where time is spent are often less intuitive.

In this article I discussed two ways to improve performance: chunk optimizations, such as the use of ASP. NET cache, and small pieces of optimizations, which often recur. The optimization of these small pieces is sometimes the most interesting. A small modification of your code will be called thousands of times. For the optimization of chunks, you may find that the whole performance has a big leap. For small pieces of optimization, you may reduce the time to a given request for a few microseconds, but if you accumulate all of your requests every day, performance gets an unexpected improvement.

Performance in the data tier

When you want to start optimizing the performance of an application, there is a decisive test that you can prioritize: does the code want to access the database? If yes, how often do you visit? Note that this test can also be applied to code that uses Web services or remote control, but I won't cover those in this article.

If you ask for a database request in one of the code paths in your code, and you find other places where you want to prioritize optimizations, such as string manipulation, stop and then perform the critical tests first. Unless you have a really bad performance problem to deal with, your time will be better spent if you spend time optimizing database connections, the amount of data returned, and the operations of your roundtrip database.

Now that I have a general overview of the relevant information, let's look at 10 tips to help your application perform better. I'll start with the ones that are most obvious for improving performance.

Techniques to return multiple result sets

Check your database code to see if you have access to the database more than once (request paths). Each of these round trips reduces the number of requests that your application can service per second. By returning multiple result sets in a single database request, you can reduce the total time that database traffic consumes. After you reduce the requests for database server management, you can also make your system more upgradeable.

In general, you can use dynamic SQL statements to return multiple result sets, and I prefer to use stored procedures. It is debatable whether the business logic should be placed in the stored procedure, but I think if the logic in a stored procedure can limit the returned data (reducing the size of the dataset, the time spent on the network connection, and the need to filter the data of the logical layer), then it is good.

Using a SqlCommand instance and its ExecuteReader method to generate a strongly typed business class, you can make the result set pointer move forward by calling NextResult. Figure 1 shows an example session that uses a defined class to generate several ArrayList. Returning only the data you need from the database can significantly reduce the memory request on your server.

1//Read the first resultset
2reader = command. ExecuteReader ();
3
4//read the data from that resultset
5while (reader. Read ()) {
6 suppliers. ADD (Populatesupplierfromidatareader (reader));
7}
8
9//Read the next resultset
10reader. NextResult ();
11
12//read the data from that second resultset
13while (reader. Read ()) {
Products. ADD (Populateproductfromidatareader (reader));
15}
16
17


Tip 2--Paging data access

Asp. NET provides a great ability: support for data paging. When paging is set in the DataGrid, a specific number of results are displayed at a time. In addition, the paging UI used to navigate between results is displayed at the bottom of the DataGrid. The paging UI allows you to navigate forward or backward through the displayed data, showing a specific number of results per page.

But there is a small problem. Paging with the DataGrid requires that all data be bound to the table. For example, your data layer would need to return all the data, and then the DataGrid would populate all the records to be displayed based on the current page. If you return 100,000 records when you use the DataGrid paging, 99,975 records will be discarded per request (assuming the capacity of each page is 25 records). As the number of records grows, the performance of the application can be greatly affected because each request must return more and more data.

One way to write better paging code is to use stored procedures. Figure 2 shows a sample stored procedure that pages the orders data tables in the Nothwind database. Overall, all you need to do here is the index of the incoming page and the capacity of the page. The database calculates the appropriate result set and returns them.


1CREATE PROCEDURE northwind_orderspaged
2 (
3 @PageIndex int,
4 @PageSize int
5)
6AS
7BEGIN
8DECLARE @PageLowerBound int
9DECLARE @PageUpperBound int
10DECLARE @RowsToReturn int
11
12--first set the ROWCOUNT
13SET @RowsToReturn = @PageSize * (@PageIndex + 1)
14SET ROWCOUNT @RowsToReturn
15
16--Set the page bounds
17SET @PageLowerBound = @PageSize * @PageIndex
18SET @PageUpperBound = @PageLowerBound + @PageSize + 1
19
20--Create A temp table to store the select results
21CREATE TABLE #PageIndex
22 (
IndexID int IDENTITY (1, 1) not NULL,
OrderID int
25)
26
27--Insert into the temp table
28INSERT into #PageIndex (OrderID)
29SELECT
OrderID
31FROM
Orders
33ORDER by
OrderID DESC
35
36--Return Total Count
37SELECT COUNT (OrderID) from Orders
38
39--Return Paged Results
40SELECT
O.*
42FROM
Orders O,
#PageIndex PageIndex
45WHERE
O.orderid = Pageindex.orderid and
Pageindex.indexid > @PageLowerBound and
Pageindex.indexid < @PageUpperBound
49ORDER by
Pageindex.indexid
51
52END
53
54

During the community service, we wrote a paging service-side control to do these data paging. You will find that I am using the ideas discussed in tip 1 to return two result sets from a stored procedure: the total number of records and the requested data.

The total number of records returned can vary depending on the request being executed. For example, a WHERE clause can be used to constrain the returned data. We must know the total number of records to be returned to calculate the total pages to be displayed in the paging UI. For example, if there are 1,000,000 total records, and a WHERE clause is used to filter the records to 1,000 records, the paging logic needs to know the total number of records to properly submit the paging UI.


Tip 3--Connection Pool

Establishing a TCP connection between your Web application and SQL Server can be an expensive operation. Microsoft developers have been using connection pooling for some time, which allows them to reuse connections to the database. Instead of establishing a new TCP connection for each request, it is better to establish a new connection only if there is not one available connection in the connection pool. When the connection is closed, it returns to the connection pool-it also maintains a connection to the database, rather than destroying the TCP connection completely.

Of course you need to be careful about leaking connections. Always close your connection when you are finished using them. I repeat: no matter who has said about Microsoft. NET Framework, you must always explicitly call the close or Dispose method on your connection when you are finished using it. Do not trust the common language Runtime (CLR) to clean up and shut down your connection at a predetermined time. The CLR eventually destroys the class and forces the connection to close, but you cannot guarantee when the garbage collection mechanism on the object will actually execute.

To achieve the best results with connection pooling, you need to follow a few rules. First, open a connection, complete the work, and then close the connection. If you have to (preferably application tip 1) It is also possible to open and close several connections for each request, which is much better than keeping the connection open and passing it on to several different methods. Second, use the same connection string (if you are using integrated authentication, of course, you need the same thread identity). If you do not use the same connection string, such as a different custom connection string for a logged-on user, you cannot get the same optimal value provided by the connection pool. And if you use integrated authentication to mimic a large number of users, your connection pool will be much less efficient. The. NET CLR data performance counters are useful when trying to track any performance issues related to connection pooling.

Whenever your application connects to a resource, such as a database, or runs in another process, you should optimize by concentrating on the time it takes to connect to the resource, the time it takes to send and receive the data, and the number of roundtrip and database times. Optimizing any type of process jump in your application is the first step to starting to achieve better performance.

The application layer contains the logic that connects to your data layer and transforms the data into meaningful class instances and logical processes. For example, in a community server, this is where you generate a forum or a collection of threads, and apply business rules such as licensing, and more importantly, where the buffer logic is executed.

Skill 4--asp. NET Buffering API

The first thing to consider before you start writing the first line of code for your application is to maximize and leverage the cache features of ASP.


If your component is running in an ASP. NET application, you just need to simply reference System.Web.dll in your application project. Use the Httpruntime.cache property when you need to access the cache (this object can also be accessed through Page.cache and Httpcontext.cache).

There are several principles for using cached data. First, if the data can be used multiple times, then caching it is a good choice. Second, if the data is generic and not for a particular request or user, caching it is a good choice. If the data is user or request specific, but his lifetime is very long, then it can also be cached, but may not be used frequently. Third, a frequently overlooked principle is that sometimes you can cache too much. Typically on a x86 computer, in order to reduce the likelihood of an out-of-memory (out-of-memory) error, you will want to run a process that uses no more than 800MB of private bytes. Therefore, the cache should be restricted. In other words, you may need to reuse the results of a calculation once, but if that calculation requires 10 parameters, you may want to try to cache 10 permutations, which can cause problems. Out-of-memory errors caused by over-caching are the most common in ASP, especially for large datasets.

Caching has several great features that you need to know about. First, the cache implements the least recently used algorithm, enabling ASP. NET to force cache cleanup when memory runs inefficiently-Automatically delete unused items from the cache. Second, the cache supports expired dependencies that can be forced to expire. These dependencies include time, keys, and files. Time is often used, but for ASP. NET 2.0, a more powerful new failure type is introduced: Database Cache invalidation. It refers to automatically deleting items in the cache when the data in the database changes. For more information about database cache invalidation, see the Dino Esposito cutting Edge column of the MSDN Magazine July 2004. To understand the architecture of your cache, see Figure 3.


Tip 5-Cache per request

In the earlier part of this article, I mentioned that some small improvements that often traverse the code path can yield significant overall performance gains. For these little improvements, one of them is definitely my favorite, and I'll call it "cache per request".

The caching API is designed to cache data for a longer period of time, or to cache until certain conditions are met, but per-request caching means that the data is cached only for the duration of the request. For each request, you frequently access a particular code path, but the data is only extracted, applied, modified, or updated once. This sounds somewhat theoretical, so let's give a concrete example.

In a Community Server forum application, each of the servers that are used on the page requires personalized data to determine what looks, what style sheets to use, and other personalization data. Some of these data can be cached for long periods of time, but some data is fetched only once for each request and then reused multiple times during the request, such as the appearance of the control.

To achieve per-request caching, use ASP. HttpContext. For each request, an HttpContext instance is created that can be accessed from anywhere in the HttpContext.Current property during the request. The HttpContext class has a special Items collection property, and the objects and data added to this items collection are cached only for the duration of the request. Just as you can use caching to store frequently accessed data, you can also use Httpcontext.items to store data that is used only on a per-request basis. The logic behind it is very simple: the data is added to the Httpcontext.items collection when it does not exist, and in subsequent lookups, it simply returns the data in the Httpcontext.items.


Tip 6-Background processing

The path to the code should be as fast as possible, right? There may be times when you find that you are performing a very great amount of resources for a task that is executed for each request or every n requests. There are some examples of sending e-mail messages or analyzing and validating incoming data.

When parsing ASP. NET Forums 1.0 and rebuilding the content that made up the community server, we found that the code path for posting new posts was very slow. Each time a new post is posted, the application first needs to make sure that there are no duplicate posts, and then must analyze the post using the bad word filter, analyze the Post's word metalized, tag and index The post, add the post to the appropriate queue when requested, verify the attachment, and finally, after the post is published, Send email notifications to all subscribers immediately. It is clear that this involves a lot of operations.

The study found that most of the time was spent on indexing logic and sending e-mails. Indexing posts is a time-consuming operation, and people find that the built-in System.Web.Mail feature connects to an SMTP server and then sends e-mail continuously. When the number of subscribers to a particular post or subject area increases, the time it takes to perform the Addpost feature is also getting longer.

E-mail indexing is not required for each request. Ideally, we want to batch this operation, index 25 posts at a time, or send all e-mails every five minutes. We decided to use the code I used to prototype the data cache invalidation, which was eventually included in Visual Studio 2005.

The Timer class in the System.Threading namespace is useful, but not very well known in the. NET Framework, at least for WEB developers. Once created, the Timer class invokes the specified callback for a thread in ThreadPool at a configurable interval. This means that you can set the code so that it can be executed without an incoming request to the ASP. This is an ideal scenario for background processing. You can also perform operations such as indexing or sending e-mail in this background process.

However, there are several problems with this technique. If the application domain is unloaded, the timer instance stops firing events. In addition, because the CLR has a hard standard for the number of threads per process, there may be situations where a heavily loaded server might not guarantee that the thread will continue to complete operations and, to some extent, may cause delays. ASP. NET attempts to minimize the chances of this happening by keeping a certain number of available threads in the process and using only a portion of the bus path for request processing. However, if you have many asynchronous operations, this can be a problem.

There is not enough room to place the code, but you can download an easy-to-understand example, the URL is www.rob-howard.net. Check out the slides and demos in the Blackbelt TechEd 2004 demo.

Tip 7-page output caching and proxy server

ASP. NET is your presentation layer (or your presentation layer); It consists of pages, user controls, server controls (HttpHandlers and httpmodules), and the content they generate. If you have an ASP. NET page that generates output (HTML, XML, images, or any other data), and you run this code for each request, it produces the same output, so you have an excellent alternative to the page output cache.

Add the following line to the top of the page:

<%@ page OutputCache varybyparams= "None" duration= "%>"

You can efficiently generate an output for this page and then reuse it for a maximum of 60 seconds, where the page will be re-executed and the output will be added to the ASP. This behavior can also be done by using some low-level programmable APIs. There are several configurable settings for the output cache, such as the VaryByParams property that you just talked about. VaryByParams is just being requested, but also allows you to specify an HTTP GET or http POST parameter to change the cache entry. For example, just set varybyparam= "report" to Default.aspx? Report=1 or default.aspx? report=2 the output cache. You can also specify additional parameters by specifying a semicolon-delimited list.

Many people don't realize that when output caching is used, an ASP. NET page also generates some HTTP header headers that flow down to the cache server, such as Microsoft Internet Security and Acceleration Server or the header header used by Akamai 。 After the HTTP cache table header is set, the document can be cached on those network resources, and client requests can be satisfied without having to return to the original server.

Therefore, using page output caching does not make your application more efficient, but it may reduce the load on the server because the downstream streaming caching technology caches the document. Of course, this can only be anonymous content, and once it becomes a downstream stream, you will never see these requests again and will no longer be able to perform authentication to block access to it.



Tip 8-run IIS 6.0 (even if you just want to use kernel caching)

If you are not running IIS 6.0 (Windows Server 2003), you are missing some good performance enhancements in the Microsoft WEB server. In tip 7, I discussed the output cache. In IIS 5.0, the request is through IIS and then into ASP. When it comes to caching, HttpModule in ASP. NET receives the request and returns the contents of the cache.

If you are using IIS 6.0, you will find a nice little feature called the kernel cache, which does not require any code changes to ASP. The IIS kernel cache receives a copy of the cached data when the request is output cached by ASP. When a request comes from a network driver, the kernel-level driver (no context switches to user mode) receives the request and, if cached, flushes the cached data to the response and finishes execution. This means that when you use the kernel-mode cache with IIS and the ASP. NET output cache, you will see performance results that are not convincing. During the development of ASP. Visual Studio 2005, I was a development manager responsible for ASP. The developer does the work, but I want to see all the reports that are done every day. Kernel-mode caching results are always the most interesting. The most common feature is that the network is full of request/response, while the IIS runtime has only about 5% CPU utilization. This is so shocking! Of course, there are other reasons to use IIS 6.0, but kernel-mode caching is one of the most obvious.



Tip 9-Use Gzip compression

Although using gzip is not necessarily a server performance tip (because you might see an increase in CPU usage), using gzip compression can reduce the number of bytes sent by the server. This makes people feel that the page speed is faster, and also reduce the amount of bandwidth. Depending on the data being sent, the degree to which it can be compressed, and whether the client browser is supported (IIS only sends gzip-compressed content to clients that support gzip compression, such as Internet Explorer 6.0 and Firefox), your server can serve more requests per second. In fact, almost every time you reduce the number of returned data, you increase the number of requests per second.

Gzip compression is already built into IIS 6.0, and its performance is much better than gzip compression used in IIS 5.0, which is good news. Unfortunately, when you try to open gzip compression in IIS 6.0, you may not be able to find this setting in the properties dialog for IIS. The IIS team placed excellent gzip functionality in the server, but forgot to include a management UI to enable the feature. To enable gzip compression, you must drill down into the XML configuration settings of IIS 6.0 (so that it does not cause heart weakness). Incidentally, thanks to OrcsWeb Scott Forsyth, he helped me raise the issue of the Www.asp.net server hosted on OrcsWeb.

This article does not tell the steps, please read Brad Wilson's article, the URL is IIS6 Compression. There is also a knowledge base article about enabling compression for aspx, the URL is enable ASPX Compression in IIS. However, you should note that because of some implementation details, you cannot have both dynamic compression and kernel caching in IIS 6.0.


Tip 10-Server Control view state

View state is an interesting name that represents an ASP. NET that stores some state data in the hidden output field of the generated page. When the page is sent back to the server, the server can parse, validate, and apply this view-state data back to the control tree of the page. View state is a very powerful feature because it allows the state to be persisted with the client, and it does not require a cookie or server memory to save the state. Many ASP. NET server controls use view state to maintain settings that are created during interaction with page elements, such as saving the current page that is displayed when paging through data.

However, there are some drawbacks to using view state. First, when a page is serviced or requested, it increases the total load on the page. Additional overhead is also incurred when serializing or de-serializing view-state data that is sent back to the server. Finally, view state increases the memory allocation on the server.

Several server controls have a tendency to overuse view state and use it even when not needed, most notably the DataGrid. The default behavior of the ViewState property is enabled, but it can be turned off at the control or page level if you do not need it. Within the control, simply set the EnableViewState property to False, or use the following settings on the page to set it globally:

<%@ page enableviewstate= "false"%>

If you do not send back the page, or if you always regenerate the controls on the page for each request, you should disable view state at the page level.


Summary

I've told you some tips I think are helpful when writing high-performance ASP. As I mentioned earlier in this article, this is a preliminary guideline, not the final conclusion of ASP. (For information about improving the performance of ASP. NET application, see Improving ASP. NET performance.) Only through your own hands-on experience can you find the best way to solve specific performance problems. However, in your journey, these tips should provide you with some good guidance. There is almost no absolute thing in software development, and every application is unique.

10 tips for writing a high-performance Web application

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.