Implement scalable applications through ASP. NET asynchronous programming

Source: Internet
Author: User
Tags configuration settings net thread

Http://msdn.microsoft.com/msdnmag/issues/07/03/WickedCode/Default.aspx? Loc = ZH # void

Do you want to know the secret? What is the secret? Once revealedCommunityThis caused a huge response and caused Microsoft opponents to send "Aha !" Is it true?

Most websites built using ASP. NET do not have good scalability. They are subject to self-imposed "glass ceilings", which limit the number of requests they can process per second. The scalability of these sites remains good until the traffic reaches this invisible limit. Then the throughput starts to decrease. Soon, the request starts to fail and usually returns the "server unavailable" error.

MsdnMagazines"Has been discussed for many times on its root cause. ASP. NET uses threads in the Common Language Runtime Library (CLR) thread pool to process requests. As long as there are available threads in the thread pool, ASP. NET will not have any trouble in scheduling incoming requests. However, once the thread pool is saturated (that is, all threads in the pool are busy processing requests, but no available threads), new requests must wait for the thread to be available. If the deadlock becomes serious and the queue reaches the capacity limit, ASP. NET will be helpless and new requests can only be rejected.

One solution is to increase the thread pool limit to create more threads. This is a method that developers often take when their customers report frequent "server unavailability" errors. Another common method is to discard faulty hardware and add more servers to the Web farm. However, increasing the number of threads or servers does not fundamentally solve this problem. In fact, it only relieves the existing design problems temporarily, not in ASP. NET, but in actual site implementation. For apps that cannot be expandedProgramThe actual problem is the lack of threads. It is the problem that an existing thread cannot be effectively used.

A truly scalable ASP. NET Website makes full use of the thread pool. This means that the request processing thread can be executedCodeInstead of waiting for I/O to complete. If the thread pool is saturated because all threads consume CPU, you have almost no choice but to add servers.

However, most web applications can communicate with databases, web services, or other external entities, it also restricts scalability by forcing the thread pool to wait for database queries, Web service calls, and other I/O operations. Data-driven web page queries may take a few seconds to execute code, and wait for a few seconds until the database query returns. When the query is incomplete, the thread allocated to the request cannot serve other requests. This is the so-called glass roof. If you want to build a highly scalable website, this situation must be avoided. Remember: When throughput is involved, I/O will become a big problem unless handled properly.

Of course, if I/O does not destroy the thread pool, it is not a big problem. ASP. NET supports three asynchronous programming models that can be used as anti-destruction agents. For communities, these models are mostly unknown, partly because of the lack of relevant documentation. Understanding how and when to use these models is essential to building advanced websites.

Asynchronous page

Among the three asynchronous programming models supported by ASP. NET, the first and most useful is asynchronous pages. Among the three models, this is the only one for ASP. NET 2.0. Other supported models are for Version 1.0.

Here, I will not go into detail about the asynchronous page, because I have discussed it in the October 2005 issue magazine. (Msdn.microsoft.com/msdnmag/issues/05/10/wickedcode ). The conclusion is: if you have some pages that require relatively long I/O operations, they should become asynchronous pages. It takes five seconds for a page to query the database (because it returns a large amount of data and locks the target to a remote database through a large number of loaded connections ), the five seconds that the thread assigns to the request cannot be used for other requests. If each request is processed based on this, the application will soon be paused.

Figure 1Shows how the asynchronous page solves this problem. When a request arrives, ASP. NET assigns a thread to it. This request starts to be processed in this thread. When a database is selected, the request starts an asynchronous ADO. Net query and returns the thread to the thread pool. When the query is complete, ADO. Net calls back to ASP. NET, ASP. NET calls out another thread from the thread pool, and resumes processing requests.


Figure 1 Effective asynchronous page (click the image to get a smaller view)
Figure 1 Effective asynchronous page (click the image to get a larger view)

When the query is incomplete, no threads in the thread pool are used to ensure that all threads can be used for incoming requests. Asynchronous requests cannot be executed quickly. However, other requests can be executed faster because they do not have to wait for the thread to be available. When entering the pipeline, the request may cause a small delay, and the overall throughput will be increased.

Figure 2 shows the code hiding class on the asynchronous page for Data Binding Based on the SQL Server database. The page_load method calls addonprerendercompleteasync to register the start and end handlers. At the end of the Request lifetime, ASP. NET calls the begin method. This method starts an asynchronous ADO. Net query and returns immediately. Therefore, the thread allocated to the request will return to the thread pool. When ADO. Net indicates that the query has ended, ASP. NET will retrieve the thread from the thread pool (not the same as previously used) and call the end method. The end method obtains the query result, and the rest of the request is executed normally in the thread that executes the end method.

The content not shown in Figure 2 is the async = "true" attribute in the page command of Aspx. The asynchronous page should be able to prompt ASP. NET to implement the ihttpasynchandler interface on the page (which will be detailed later ). Similarly, what is not shown in Figure 2 is the database connection string, which contains its own async = "true" attribute. In this way, ADO. NET will know that it needs to perform an asynchronous query.

Addonprerendercompleteasync is a method for building asynchronous pages. Another method is to call registerasynctask. Compared with the addonprerendercompleteasync method, this method has some advantages. The most important thing is that it simplifies the task of executing multiple asynchronous I/O operations in a request. For more information about this, see the "cool code" section in April October 2005.

Asynchronous HTTP processing program

The second asynchronous programming model in ASP. NET is an asynchronous HTTP processing program. An HTTP handler is an object that acts as the request endpoint. For example, requests to aspx files are processed by HTTP handlers for aspx files. Similarly, requests to asmx files are processed by the HTTP handler that knows how to process the asmx service. In fact, ASP. NET has an HTTP handler for multiple file types. In the In machine. config), you can see these file types and the corresponding HTTP handler.

By writing a custom HTTP processing program, you can extend ASP. NET to support other file types. But what's more interesting is that you can deploy HTTP handlers in the ashx file and use them as the targets of HTTP requests. This is the correct way to build a web endpoint that dynamically generates images or retrieves images from a database. You only need to include the tag (or image control) in the page and point it to the ashx that creates or retrieves the image. Locking a target to an ashx file with a request is more effective than locking the target to An ASPX file, because the ashx file has less overhead during processing.

According to the definition, the HTTP handler can implement the ihttphandler interface. The handler that implements this interface cannot be processed simultaneously. The ashx file in Figure 3 contains an HTTP handler of this type. At runtime, terraserviceimagegrabberThe terraserver Web Service is called multiple times to convert cities and states into longitude and latitude, and to retrieve satellite images (like tiles "), then, the image is spliced together to form a composite image at the specified position.

The result is as follows:Figure 4. The displayed page contains the image control. Its imageurl attribute locks the target to the ashx file shown in figure 3. After you select a city or State and click the button, the HTTP handler converts the input to a satellite image.

The results are impressive. But there is a problem. Terraserviceimagegrabber is a perfect example of how to avoid writing HTTP handlers. Think about it. It takes several seconds (at least) for terraserviceimagegrabber to call all its Web Services and process the results. Most of the time is spent waiting for the completion of web service calls. Repeated requests to the ashx file will immediately exhaust the ASP. NET thread pool to prevent other pages in the application from being used (or at least queue them for thread availability ). You cannot use this method to build scalable applications unless you have extended hardware. However, why spend tens of thousands of dollars on the Web market when correctly written software can be used to process loads on a single server?


Figure 4 Effective terraserviceimagegrabber (click the image to get a smaller view)
Figure 4 Effective terraserviceimagegrabber (click the image to get a larger view)

HTTP handlers do not have to be synchronized. By implementing the ihttpasynchandler interface, the interface itself can be derived from ihttphandler, And the HTTP handler can be asynchronous. If used correctly, asynchronous processing programs can more effectively use ASP. NET threads. This can be done in the same way as Asynchronous pages. In fact, asynchronous pages can be used in ASP. NET to support asynchronous processing programs that advance asynchronous page dates.

Figure 5 contains the asynchronous version of the handler shown in figure 3. Async-terraserviceimagegrabber is a little complicated but highly scalable.

When ASP. NET calls the beginprocessrequest method of the processing program, it starts asynchronous processing. The beginconvertplacetolonlatpt method of the terraservice proxy allows beginprocessrequest to asynchronously call terraservice. Then, it is allocated to the thread return thread pool of the request. When the asynchronous call is completed, another thread is called up from the thread pool to execute the convertplacetolonlatcompleted method. This thread retrieves the result of the last call, performs its own asynchronous call, and then returns the thread pool. This mode repeats until all asynchronous calls are completed. In this case, the endprocessrequest method of the processing program is called, and the generated bitmap is returned to the requester.

To stop endprocessrequest until the final web service call is completed, asyncterraserviceimagegrabber returns the iasyncresult self-implementation from beginprocessrequest. If it wants to return iasyncresult returned by beginconvertplacetolonlatpt, it must call endprocessrequest (and terminate the request) when the first web service call is complete ).

Classes that implement iasyncresult and terraserviceasyncresult have public completecall methods that can be called at any time to complete the request. Generally, asyncterraserviceimagegrabber calls completecall only after the last Web service call is completed. However, if an exception is thrown for a method executed between beginprocessrequest and endprocessrequest, the handler caches the exception in the private field (_ ex) and calls completecall to terminate the request, then throw an exception from endprocessreques. Otherwise, the exception is lost and the request cannot be completed.

Because asyncterraserviceimagegrabber uses ASP. NET threads only a small part of the total time required to process requests, asyncterraserviceimagegrabber has higher scalability than similar methods in the synchronous version. Most of the time, it only waits until the asynchronous web service call is completed.

Theoretically, asyncterraserviceimagegrabber is better than terraserviceimagegrabber because it does not call the terraservice's gettile method in sequence, but concurrently. However, in fact, only two outbound calls for a given IP address can be suspended at a time, unless you increase the default maxconnection settings of the Runtime Library:

 
<System.net> <connectionmanagement> <add address = "*" maxconnection = "20"/> </connectionmanagement> </system.net>

 

Other configuration settings can also affect concurrency. For more information, see the Knowledge BaseArticle"Problems such as contention, poor performance, and deadlocks during Web Service requests from ASP. NET applications" (support.microsoft.com/kb/821268 ).

Even if only one call is executed at a time, asyncterraserviceimagegrabber is no worse than terraserviceimagegrabber. It is well designed because it uses ASP. NET threads as effectively as possible.

Asynchronous HTTP Module

The third asynchronous programming model that you may use in ASP. NET is the asynchronous HTTP module. The HTTP module is an object located in the ASP. NET pipeline. in the pipeline, it can view or even modify incoming requests and outgoing responses. Many major services in ASP. NET are implemented in the form of HTTP modules, including identity authentication, authorization, and output caching. By writing custom HTTP modules and inserting them into pipelines, you can expand ASP. NET. When you do this, you must carefully consider whether these HTTP modules should be asynchronous.

Figure 6 contains the simple and synchronous HTTP module called requestlogmoduleSource codeIt records the incoming request in a text file named requestlog.txt. Create the file in the app_data directory of the site so that you cannot browse it. (Note that ASP. NET must be used as a security entity (for example, ASPnet or network service) to write the permission to use app_data .) This module implements the ihttpmodule interface, which is the only requirement of the HTTP module. When this module is loaded, its init method registers a handler for the httpapplication. prerequesthandlerexecute event, which is triggered from the pipeline of each request. The event handler opens requestlog.txt (or creates a file if the file does not exist), and then writes a row containing targeted information about the current request to it, including the request arrival time and date, and the user name of the requester (if the request is for authentication, or if the authentication is disabled, it must contain the requester's IP address ), and the request URL. This module is registered in the

Requestlogmodule has two problems. First, the I/O file is executed every time a request is made. Second, it uses the request processing thread to execute I/O. Otherwise, the thread may be used to serve other incoming requests. This module causes throughput loss due to its simplicity. By processing I/O files in batches, you may reduce the latency. A better way is to make the module asynchronous (or it is best to batch process I/O files and make the module asynchronous ).

Figure 7 shows the asynchronous version of requestlogmodule. After the asyncrequestlogmodule is called, it will execute exactly the same work, allocate it to the request thread return thread pool, and then write the file. When the write is complete, a new thread is called up from the thread pool to complete the request.

How to Make asyncrequestlogmodule asynchronous? The init method calls httpapplication. addonprerequesthandlerexecuteasync to register the begin and end methods for the prerequesthandlerexecute event. The httpapplication class contains other addon methods for other per-request events. For example, the HTTP module can call addonbeginrequestasync to register an asynchronous handler for the beginrequest event. The beginprerequesthandlerexecute method of asyncrequestlogmodule uses the filestream. beginwrite method of the framework to start asynchronous writing. When beginprerequesthandlerexecute returns, the thread returns the thread pool.

The asyncrequestlogmodule contains some special thread synchronization logic. Multiple requests running in multiple threads may need to write log files at the same time. To ensure that concurrent writes do not overwrite each other, the asyncrequestlogmodule saves the position (_ position) of the next write in the file in the private field shared by all module instances ). Before each beginwrite call, the module reads the location from the field and updates the field to point to the first byte of the content to be written to the file. The logic for reading and updating _ position is included in the lock statement, so that more than one thread can execute it each time. This prevents another thread from reading the location before a thread has the opportunity to update the location.

Now let's talk about the shortcomings. For beginwrite of another thread in the thread pool that is not used, the isasync parameter of the filestream build function must be set to "true", as I did in the example. However, using filestream. beginwrite to start a known result of asynchronous writing cannot guarantee that the write is actually asynchronous, even if you have requested an asynchronous operation. If you are sure that synchronizing I/O is faster, WindowsReserve the right to execute asynchronous I/O files synchronously. For more information, see the Knowledge Base Article on support.microsoft.com/kb/156932. The good thing is that in windows, synchronous Write Request logs can be executed faster theoretically, minimizing the impact on host application scalability.

Summary

Asynchronous programming is a good way to use ASP. NET thread pool as efficiently as possible to build more scalable applications. In the past, I rarely saw ASP. NET developers using asynchronous programming models, partly because they do not know that these models exist. Do not make sparse documents a "Roadblock" for you. You can start to think about sparse documents asynchronously from now on. In the future, you will build better applications.

Note that this article provides C # and Visual BasicVersion of the downloadable sample code. I often receive emails asking for Visual Basic examples. This time, you don't have to ask again. I have provided an example of this version!

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.