Improved ASP. Net Site Performance-reduced long wait time

Source: Internet
Author: User
ArticleDirectory
    • Read lock request
    • Request write lock
    • Reading and Writing locks Alternate

If the server does not use up memory, CPU, or threads, the request still takes a long time to complete, it may be that the server waits for external resources, such as databases and other external resources for a long time.

In this chapter, we will discuss these issues:

    • How to use a custom counter to measure the long wait time.
    • Parallel rather than serial wait.
    • Improves session Status performance.
    • Reduce thread lock latency.
Metric wait time

Measure the frequency and duration of waiting for external resource response:

    • Run in the debuggerCodeTo set a breakpoint at the place where external resources are requested. However, you cannot use this method in the production environment, and this method can only provide a small amount of request information.
    • Use the trace class (in the space used by system. Diagnostics) to track the time spent on each request. This method provides detailed information. However, if it is used in the production environment, the cost of processing the tracing message is too high. You must merge the tracing data to find the request frequency, and the time spent is the longest.
    • Use performance counters in the code to record the frequency and average wait time of each request. These counters are lightweight and may be used in production environments.

Windows provides 28 performance counters. It is easy to add a custom counter. You can view the Real-Time Value in perfmon, just like the built-in counter.

The overhead of the counter is very small. ASP. NET, SQL Server, and window have released hundreds of counters. Even if many counters are added, the CPU overhead will remain below 1%.

This chapter uses only three common counters: simple numbers, rate per second, and time. All types of counters and how they can be used in the http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx? Ppud = 4.

There are three steps to use the counter:

    1. Create a custom counter.
    2. Integration into code.
    3. View the value in perfmon.
Create a custom counter

In this example, a page simply waits for one second to simulate waiting for external resources. We will place counters on this page.

Windows allows counters to be classified. We create a new "test counters" category for the new counter.

Here are some counters we will put on the page. They are commonly used in three types of counters.

Counter name Counter type Description
NBR page hits Numberofitem64 A 64-bit counter that records the number of visits to the page after the website is started.
Hits/second Rateofcountspersecond32 Visits per second
Average wait Averagetime32 The interval between waiting for resources.
Average wait Base Averagebase Tool counters required by average wait

There are two ways to create a counter and a "test counters" category:

    • Using Visual Studio: This method is fast, but if you want to apply the same counter in multiple environments, such as the development environment and production environment, you must add this counter in multiple environments.
    • Programming: it is easier to apply the same counter in multiple environments.
Use Visual Studio to create a counter

Omitted

Programming to create counters

From the maintenance point of view, it is best to use the global. asax FileProgramIt is best to create a counter at startup. However, you must consider the application pool in which the performance monitor user group runs.

Another method is to create a counter in a separate console program. The administrator can run this program on the server to create counters. The Code is as follows:

Using system; using system. diagnostics; namespace createcounters {class program {static void main (string [] ARGs) {countercreationdatacollection CCDC = new countercreationdatacollection (); countercreationdata CCD = new countercreationdata ("NBR page hits ", "Total number of page hits", performancecountertype. numberofitems64); CCDC. add (CCD); CCD = new countercreationdata ("hits/second", "Total number of page hits/sec", performancecountertype. rateofcountspersecond32); CCDC. add (CCD); CCD = new countercreationdata ("average wait", "average wait in seconds", performancecountertype. averagetimer32); CCDC. add (CCD); CCD = new countercreationdata ("average wait base", "", performancecountertype. averagebase); CCDC. add (CCD); If (performancecountercategory. exists ("test counters") {performancecountercategory. delete ("test counters");} performancecountercategory. create ("test counters", "counters for test site", performancecountercategorytype. singleinstance, CCDC );}}}
Use counters in code
Using system; using system. diagnostics; public partial class _ default: system. web. UI. page {protected void page_load (Object sender, eventargs e) {performancecounter nbrpagehitscounter = new performancecounter ("test counters", "NBR page hits", false); nbrpagehitscounter. increment (); performancecounter nbrpagehitsperseccounter = new performancecounter ("test counters", "hits/second", false); nbrpagehitsperseccounter. increment (); stopwatch Sw = new stopwatch (); Sw. start (); // simulate actual operation system. threading. thread. sleep (1000); Sw. stop (); performancecounter waittimecounter = new performancecounter ("test counters", "average wait", false); waittimecounter. incrementby (SW. elapsedticks); performancecounter waittimebasecounter = new performancecounter ("test counters", "average wait base", false); waittimebasecounter. increment ();}}
View custom counters in perfmon

. Refer to previous articles.

Parallel wait

If the website needs to wait for multiple external resources to wait for response, and these requests are not mutually dependent, You can initialize these requests at the same time and wait in parallel, instead of waiting in serial mode. If three Web services are required, each of which takes 5 seconds, it takes 5 seconds instead of 15 seconds to wait in parallel.

Asynchronous code can be used to easily implement parallel waiting. When registering each asynchronous task, pass the true parameter to the executeinparallel parameter of the pageasynctask constructor:

 
Bool executeinparallel = true; pageasynctask = new pageasynctask (beginasync, endasync, null, null, executeinparallel); registerasynctask (pageasynctask );
Obtain multiple result sets from the database

Refer to previous articles.

Reduces overhead for using the external session Mode

If session status is used on the server farm, StateServer or sqlserver State may be used, instead of inproc mode, because requests from the same visitor may be processed by different servers.

When ASP. NET starts to process a request, it obtains the current session status from StateServer or SQL Sever and then deserializes it. The session status is serialized at the end of the page lifecycle and stored in the StateServer or SQL Server database. In this process, ASP. NET updates the last access time of the session, which may clear the timeout session. If you use sqlserver mode, it means that each request has two rounds.

Reduce Database Access

You can reduce database access by setting the page command to false or readonly:

 
<% @ Page enablesessionstate = "true"... %>

Enablesessionstate can take these values:

    • True: default value. One database is accessed twice.
    • False: the session is not read. To prevent the session from being expired, the session needs to be updated at the end of the page, so you only need to access the database once.
    • Readonly: obtains and deserializes the session status when the page starts. However, when the page ends, the session status is not updated. You only need to access the database once. In addition, this mode uses a read lock to allow multiple read-only requests to access the session Status at the same time. Therefore, when processing requests from the same user, the lock competition is avoided.
Set enablesessionstate

Enablesessionstate can be set in the page command:

<% @ Page enablesessionstate = "readonly" %>

You can also set the session mode of the entire website in Web. config:

 
<Configuration> <system. Web> <pages enablesessionstate = "readonly"/> </system. Web> </configuration>

You can reload the default value in the page command on each page.

Bytes: less serialization and transmission overhead

Do not store objects with multiple fields in a session. Each field is stored separately. This provides the following benefits:

    • Serialization .. Net simple type, for example, String, Boolean, datetime, timespan, int16, int32, int64, byte, Char, single, double, decimal, sbyte, uint16, uint32, uint64, guid, and inptr are extremely fast and efficient. It is very slow to serialize object types that use binaryformatter.
    • Only a single field to be accessed is allowed. Fields not accessed are not updated, saving serialization and transmission time.

Assume there is a class:

 
[Serializable] private class person {Public String firstname {Get; set;} Public String lastname {Get; Set ;}}

In the session, obtain and store the data as follows:

// Get object from sessionperson myperson = (person) session ["myperson"]; // make changesmyperson. lastname = "Jones"; // store object in Sessionsession ["myperson"] = myperson;

This will use binaryformatter to deserialize/serialize the entire myperson object and transmit it across the session storage server.

Another method:

 private class sessionbackedperson {private string _ id; Public sessionbackedperson (string ID) {_ id = ID;} private string _ firstname; Public String firstname {get {_ firstname = httpcontext. current. session [_ ID + "_ fi Rstname "]. tostring (); Return _ firstname;} set {If (value! = _ Firstname) {_ firstname = value; httpcontext. current. session [_ ID + "_ firstname"] = value ;}} private string _ lastname; Public String lastname {get {_ lastname = httpcontext. current. session [_ ID + "_ lastname"]. tostring (); Return _ lastname;} set {If (value! = _ Lastname) {_ lastname = value; httpcontext. Current. session [_ ID + "_ lastname"] = value ;}}

This class stores each attribute in a session. It must know its ID when it is created so that it can construct a unique session key. When setting attributes, the session object is accessed only when the new value and the old value are different.

The result of this method is to only store individual basic types, which are faster than the whole object serialization. The field value in the session will be updated only when these fields are actually updated.

Use:

 
Protected void page_load (Object sender, eventargs e) {sessionbackedperson myperson = new sessionbackedperson ("myperson"); // update object, and session, in one go. // only touch lastname, not firstname. myperson. lastname = "Jones ";}
Completely eliminate the dependency on sessions

The biggest benefit of a session is that the session status is stored on the server, which is difficult for unauthorized users to access and modify. Then, if this is not a problem, here are some other options to remove the session status and its overhead:

    • If you do not need to save a lot of meeting data, use cookies.
    • Store sessions in viewstate, which requires a larger bandwidth, but reduces database traffic.
    • Use Ajax asynchronous call to replace the whole page refresh, so that session information can be saved on the page.
Thread lock

If a lock is used to ensure that only one thread can access resources, other threads must wait for the lock to be released.

Use the following counters in the. net clr locksandthreads category to view the lock information:

Category:. Net CLR locksandthreads

Contention rate/sec Rate of failed attempts to get the hosting lock during runtime.
Current Queue Length Number of threads waiting for hosting locks recorded last time

 

A continuous failure in applying for a lock by a thread is a cause of delay. You can consider using the following methods to reduce these latencies:

    • Lock duration reduction
    • Use the granular lock
    • Use System. Threading. Interlocked
    • Use readerwriterlock
Lock duration reduction

Apply for a lock before accessing shared resources. Release the lock immediately after the access is completed.

Use the granular lock

If the C # Lock statement or monitor object is used, the lock is as small as possible.

Lock (protectedobject) {// protected code}

The following code is short:

 
Try {monitor. Enter (protectedobject); // protected code...} finally {monitor. Exit (protectedobject );}

There is no problem with this writing, as long as the locked object is only related to the protected code. Lock only private or internal objects. Otherwise, some irrelevant code may lock the same object to protect other pieces of code, which may lead to unnecessary latency. For example, do not lock this:

 
Lock (this) {// protected code ...}

Lock a private object:

Private readonly object privateobject = new object (); Public void mymethod () {lock (privateobject) {// protected code ...}}

To protect static code, do not lock the class:

 
Lock (typeof (myclass) {// protected code ...}

Lock static objects:

Private Static readonly object privatestaticobject = new object (); Public void mymethod () {lock (privatestaticobject) {// protected code ...}}
Use System. Threading. Interlocked

If the protected Code only adds or removes an integer, adds an integer to another integer, or exchanges two values, consider replacing the lock with the system. Threading. Interlocked class. Interlocked performs faster than the lock.

For example, do not

 
Lock (privateobject) {counter ++ ;}

Usage:

Interlocked. increment (ref counter );
Use readerwriterlock

If most of the accessed protected object threads read-only the object, and a relatively small number of threads update the object, consider using readwriterlock. This allows multiple read-only threads to access protected code, but only one write thread to access it.

Read lock request

When readerwriterlock is used, readerwriterlock is declared at the class level:

 
Static readerwriterlock = new readerwriterlock ();

Call acquirereaderlock to request a read lock in a method. You can specify the timeout value. When a timeout occurs, an applicationexception is thrown. Call releasereaderlock to release the lock. The lock can be released only when the lock is actually available, that is, the lock has not timed out. Otherwise, an applicationexception will be thrown.

Try {readerwriterlock. acquirereaderlock (millisecondstimeout); // read the protected object} catch (applicationexception) {// The Reader lock request timed out .} finally {// ensure that the lock is released, provided there was no // timeout. if (readerwriterlock. isreaderlockheld) {readerwriterlock. releasereaderlock ();}}
Request write lock

Call acquirewriterlock to request the read lock. Call realeasewriterlock to release the lock:

Try {readerwriterlock. acquirewriterlock (millisecondstimeout); // update the protected object} catch (applicationexception) {// The writer lock request timed out .} finally {// ensure that the lock is released, provided there was no // timeout. if (readerwriterlock. iswriterlockheld) {readerwriterlock. releasewriterlock ();}}

If the code holds a read lock and then needs to update the protected object, you can release the read lock before requesting the write lock, or call the updatetowriterlock method. You can also call downgradefromwriterlock to downgrade from the write lock to the read lock to allow other read locks to start reading.

Reading and Writing locks Alternate

Although multiple threads can read protected objects at the same time, exclusive access is required to update protected objects. When a thread updates an object, other threads cannot read or update the same object. The threads waiting for reading locks and waiting for writing locks are allocated in different queues. When the write lock releases the lock, all threads waiting for the read lock can access the object. When the read locks are released, the next thread waiting for the write lock may get the write lock.

To ensure that the write thread can get the write lock when a thread continuously requests the read lock, if a new thread requests the read lock and other read threads are already executing the code, the new thread must wait, until the next write thread completes the operation. Of course, if there is no thread waiting for the write lock, the new read thread can immediately get the read lock.

Optimized disk write

If the website creates many new files on the disk, such as files uploaded by visitors, consider these performance improvement measures:

    • Avoid disk header search
    • Use filestream. setlength to avoid fragmentation
    • 64 K buffer
    • Disable 8.3 file name
Avoid disk header search

You do not need to move the Read/Head During sequential writing, which is much faster than random access. If you only write files and do not read them, use a dedicated thread to write them to a dedicated drive. In this way, other processes will not move the read/write header of the drive.

Use filestream. setlength to avoid fragmentation

If multiple threads write files at the same time, the space occupied by these files will be staggered, leading to fragmentation.

To avoid this situation, use the filestream. setlength method to reserve sufficient space before writing.

If you use the ASP. NET fileupload control to receive files, you can use the following code to get the file length:

 
Int bufferlength = fileupload1.postedfile. contentlength;
64 K buffer

The NTFS file system uses a 64kb internal buffer. The filestream constructor allows you to set the buffer size for file writing. You can set the filestream cache size to 64 KB to achieve higher performance.

Disable 8.3 file name

To maintain backward compatibility with MS-DOS, the NTFS file system maintains a 8.3 file name for each file or directory. This will incur some additional overhead, because the system must ensure that the 8.3 file name must be unique, so you must check other file names in the directory. If the number of files in a directory exceeds 20000, this overhead is significant.

Before disabling the 8.3 file name, make sure that no program depends on these names in the system. Perform a test on the same operating system.

Run this command in the command line (back up the Registry first ):

 
Fsutil Behavior Set disable8dot3

Restart the machine.

More resources
    • Why disabling the creation of 8.3 DOS file names will not improve performance. Or will it?
      http://blogs.sepago.de/helge/2008/09/22/why-disabling-the-creation-of-83-dos-file-names-will-not-improve-performance-or-will-it/.
    • fast, scalable, and secure session state management for your web applications
      http://msdn.microsoft.com/en-us/magazine/cc163730.aspx.
    • Performance Counter type reference
      http://www.informit.com/guides/content.aspx? G = DOTNET & seqnum= 253.
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.