Are there any databases with no exceptions, no CPU exception, no memory usage exception, no GC count exception, no hard disk IO exception, no bandwidth exception, no line exception, no packet loss, but is it a complaint? In addition, there is a sudden increase in user complaints. When a user complained slowly, your access was fast and the local traffic could not be reproduced? Today, you are so lucky to visit the blog Park. Maybe you have an answer here-if your site dynamically processes images or other non-webpage resources that would not have been dynamically processed. Unexpectedly, it was the Session that caused the decline in ASP. NET Website performance!
The access traffic to a website in our company has been very high. A few years ago, we found that the customer often complained slowly, and we have been troubleshooting and solving this problem. We have searched and solved the line issues, database connection leaks, database deadlocks, indexes, and program optimization problems. However, this problem still exists. For example, in IIS logs, you will often see access with a time-taken greater than 10 seconds. Recently, our KPI requirements have to solve this problem, and we have to embark on another difficult troubleshooting journey.
The reason for this difficulty is that it is almost impossible to reproduce in the local environment. One is that this phenomenon is of a sudden onset, and the other is that the local traffic or data volume is not large enough. We also tried to load the online server database locally, and then replayed the IIS Log file on the server. The result is indeed that the time-taken in the IIS Log is also relatively long, however, the performance of the local server is not as good as that of the online server. For example, I/O is very poor, so I cannot tell you what the problem is. It is not convenient for online servers to use Dump in the form of Search: first, the site will lose response within a few minutes because of a Dump on the line, so our customer service phone will be cracked; another cause is the issue of the outbreak. We cannot keep an eye on the performance, and then perform Dump when the problem occurs. In addition, the performance cannot be seen, because those access requests with a long response time are extremely fast. Inevitably, we can only insert some debugging and Log Code into the code to expect some useful information.
At the beginning, we thought the most likely cause was database blocking. For example, if a certain access locks a database object, such as a table or a few rows, if a specific page is accessed at this time, it may be slow. Therefore, a pile of code is inserted into the database layer. These codes may be used when the number of database connections is large or the connection time of a database is very long, output the current access statement, connection duration, and current stack of all database connections to the file. At the same time, we also opened SQL profiler to monitor the database and record all the records that lasted for more than 1 second. However, after one day of operation, I found that nothing was recorded, but the IIS logs still showed many accesses over 10 seconds in this period. At this time, we realized that the direction may be wrong.
Next, we start to plug in another piece of code: An IHttpModule. This module only intercepts all the events in the full lifecycle of each page access, such as BeginRequest and PreAuthenticateRequest. At the same time, a timer is set at the beginning of BeginRequest, and an event is triggered every second to record the current stack of all threads collected by this module during this access. Finally, if the access time exceeds 5 seconds during the EndRequest, all previously intercepted information will be output to the file. This suddenly becomes very clear, for example, the output segment below) is a very typical situation:
- #Steps:
- #Fields: date time threadId stepName
- #---------------------------------------------------
- 2009-07-09 16:48:01.752 0024 BeginRequest
- 2009-07-09 16:48:01.752 0024 AuthenticateRequest
- 2009-07-09 16:48:01.752 0024 PostAuthenticateRequest
- 2009-07-09 16:48:01.752 0024 AuthorizeRequest
- 2009-07-09 16:48:01.752 0024 PostAuthorizeRequest
- 2009-07-09 16:48:01.752 0024 ResolveRequestCache
- 2009-07-09 16:48:01.752 0024 PostResolveRequestCache
- 2009-07-09 16:48:01.752 0024 PostMapRequestHandler
- 2009-07-09 16:48:06.284 0007 AcquireRequestState
- 2009-07-09 16:48:06.284 0007 PostAcquireRequestState
- 2009-07-09 16:48:06.284 0007 PreRequestHandlerExecute
- 2009-07-09 16:48:06.284 0007 EndRequest
- #---------------------------------------------------
- #End of steps.
That is to say, there is a large wait time after PostMapRequestHandler and before AcquireRequestState. The stack behind this report is strange: thread 7 is blank from the first snapshot capture to the end! Even in some other reports, we may even find that this thread has been assigned to handle the work of other pages. The call in the stack clearly indicates that it is the code of another aspx page ). Result 1 two keywords, Google "PostMapRequestHandler" and "AcquireRequestState", found another victim with performance impact similar to ASP. NET:
- http://forums.iis.net/t/1147300.aspx
The owner is An aspx page with several iframe, and each iframe accesses the Aspx page under the same Web application. This is because pages in iframe pop up one by one, especially when these pages are relatively slow. Like what I have intercepted here, there is a long gap between the PostMapRequestHandler event and the AcquireRequestState. After finding another post:
Http://www.microsoft.com/communities/newsgroups/en-us/default.aspx? Dg = microsoft. public. dotnet. framework. aspnet & mid = 7f56033f-caac-47c2-bd9c-95512aa14b47
It turns out that, before AcquireRequestState, the current page will be processed only after the previous page with the same SessionId has been processed. The root cause is that the Session object under the same SessionId should not be written at the same time, otherwise it will be completely messy. The principle is the same as that of multi-thread competition. Therefore, the same SessionId page or IHttpHandler will be executed in sequence.
Now, the truth is revealed again! Maybe there are other problems, and the next time we make a big announcement) in our system, for special reasons, we will use Asp to output images. net to process, for example, adding some suitable cache tags, or even dynamically generating image output. Surprisingly, the total time consumed by this dynamic output is less than 100 milliseconds, so do not say that dynamic generation is a bad implementation method ). However, the Asp. Net underlying layer considers that these accesses require write operations on the Session, so they are suspended before the AcquireRequestState and wait until the last Session ID access ends. As you can imagine, an excessive number of images will lead to a long queue or even a long queue. If you access the next page before the end of the queue, and the system does not lose the previous queue, the access will become longer. How can this problem be solved? I found the exact description at a time:
Http://msdn.microsoft.com/en-us/library/ms178581.aspx
Note the following:
Concurrent Requests and Session State
Access to ASP. NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. however, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. the second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out .) if theEnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. however, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.
That is to say, for pages, we can simply set EnableSessionState = "false" or EnableSessionState = "ReadOnly" in <% @ Page %> of Aspx ", the problem can be mitigated. The previous setting will disable access to the Session, and the other setting will only allow read-only access, but you cannot perform write operations on the Session ). In the IHttpHandler we mentioned just now, you do not need to write the Session to process the image, but you need to read the Session according to the status, to solve the problem.
The above references do not explain how to set IHttpHandler which is not a Page. For a custom class that implements the IHttpHandler interface, you only need to implement the IReadOnlySessionState at the same time to achieve the effect of EnableSessionState = "ReadOnly. At the same time, if the IRequiresSessionState is not implemented, the effect is equivalent to EnableSessionState = "false.
Note: what I mentioned in this Article does not mean that you have used the Session in the Code. ASP. NET does not scan your code to see if you have accessed the Session or locks it when you first access the Session. ASP. NET first applies for this lock before the AcquireRequestState event-as long as your page does not set EnableSessionState = "false" or EnableSessionState = "ReadOnly ", or your IHttpHandler implements the IRequiresSessionState but does not implement the IReadOnlySessionState interface. Many people in the reply said, "Is it okay if I don't need a Session ?" Or "I never use sessions". It is totally wrong to think so. It can only be said that you do not understand the mechanism behind this, or even the Asp.net lifecycle is unclear. The reason why Asp. Net is locked before your page code starts to be executed is to ensure the integrity of the entire environment and avoid partial execution. Of course, as mentioned in some of the above references, you can write a SessionProvider by yourself without any lock work, but there is certainly a risk of uncertainty in doing so. At that time, you can only bear it by yourself, and it is more difficult to reproduce and debug.
ASP. NET Website Performance Analysis Note:
Many may know what Session is, and many may know ASP. NET lifecycle, such as the search for "PostMapRequestHandler AcquireRequestState". Many Chinese pages will introduce the events and lifecycles of the HttpApplication class. When it comes to Session, it may cause site performance problems in special circumstances. It seems that I am the first in the Chinese field. Of course, this problem may be relatively biased, because generally, users only process the Aspx page instead of the image, and even have fewer opportunities to dynamically output images using the Aspx page, it seems that only the only comrade mentioned in this Article has proposed the English language.
However, a very common scenario is affected by this problem, that is, the "Verification Code ". If the verification code is generated slowly and the client browser selects persistent connection while the Server accepts persistent connection, the access speed to the next page may be affected before the verification code is output. In turn, we can also often experience that the speed of verification code is always very slow and always jumps out, especially when the current page is particularly complex, it seems that no verification code is displayed after the page is loaded. I guess the problem is one of the reasons.
However, the verification code problem is not very well solved, because in order to avoid information leakage, the answer to the Verification Code usually exists in the Session, and the general design is to access the verification code image, the answer to the Verification code is written into the Session. Therefore, unfortunately, the solution mentioned in this Article does not work, at least not directly. Is there any medicine to save this problem? Yes, of course. How to save it? Well, you can use your own brains. It's just a few minutes.
- ASP. NET Error Handling Mechanism
- ASP. NET multi-attachment upload and attachment editing
- Secrets of performance and scalability in ASP. NET
- ASP. NET 3.5 chart controls
- Describes the four statuses of ASP. NET.