Optimizing Web Classes


The previous topics in this chapter apply when using the Web classes, but since the Web classes implement a higher level protocol, as well as offer more functionality such as authentication, there are additional considerations. In this section, we ll cover threading with the Web classes, connection management, performance considerations using the GET and POST verbs, asynchronous I/O, and authentication.

Managing Threads and Connections

Using the asynchronous I/O pattern offers the most bang for the buck in terms of increasing performance with the Web classes. However, it is important to understand how asynchronous calls are made as the process can influence application design. When an asynchronous call completes, a thread from the thread pool that runs the delegate associated with the operation is consumed. The thread pool is a limited resource that can be exhausted if you re not careful.

Recall from Chapter 10 that the ServicePointManager enforces a limit of two concurrent connections per application domain per host. This can cause a few problems. First, in the case of ASP.NET, the server can be underutilized as the front-end requests are bottlenecked on the two threads limit. Second, the application may become deadlocked because the ASP.NET worker threads are waiting for requests to complete, except those requests require additional threads for additional operations so they can complete.

Note  

In version 1.0 and 1.1 of the .NET Framework, blocking Web calls are implemented using asynchronous calls. The blocking call issues an asynchronous request and then waits until it completes, which means even blocking calls use the thread pool resource. In the next major release of the .NET Framework, blocking HTTP calls will be true blocking calls.

A couple of solutions prevent a deadlock situation. The first solution is to move the methods being called from ASP.NET into a local dynamic link library (DLL) so that they can be invoked directly. The second solution is to use the ServicePointManager to increase the number of allowed concurrent connections. The global defaults can be modified by changing the DefaultNonPersistentConnectionLimit and DefaultPersistentConnectionLimit properties on the ServicePointManager class. Or, if an application needs to change the connection limits for a specific destination, the ServicePoint.ConnectionLimit can be changed. Increasing the connection limit to 10 or 12 is usually sufficient for ASP.NET and other middle- tier scenarios. The following code sample creates a request and sets the connection limit to the given destination:

C#

 HttpWebRequestrequest= HttpWebRequest)WebRequest.Create("http://www.foo.com"); request.ServicePoint.ConnectionLimit=12; request.BeginGetResponse(newAsyncCallback(ResponseCallback),request); 

Visual Basic .NET

 DimrequestAsHttpWebRequest=WebRequest.Create(http://www.foo.com) request.ServicePoint.ConnectionLimit=12 request.BeginGetResponse(AddressOfResponseCallback,request) 

The connection limit plays a significant role in HTTP performance, as shown in Table 14-3. The table lists performance results for different values of the ServicePoint.ConnectionLimit property when making Web GET requests. In addition to the connection limit, HTTP pipelining and the Nagle algorithm play roles in performance. The numbers in Table 14-3 were measured on a 2.4-GHz Pentium 4 client running Windows XP Service Pack 1 with 512-MB memory retrieving a 1-KB file. The server was a quad processor 1.4-GHz AMD 64 server with 2-GB memory running Windows Server 2003 Service Pack 1. Both computers were on an isolated 100-MB network.

The sample application used to measure these results is entitled fastget and is located in the downloadable samples under Chap14\fastget.

Table 14-3: Web Class Performance

Connection Limit

Pipelining

Nagle

Requests per Second

MB/Second

2

No

No

2277.697

2.332

10

No

No

2760.601

2.826

20

No

No

2822.945

2.890

10

Yes

No

3906.25

4.000

20

Yes

No

3881.988

3.975

10

No

Yes

2712.674

2.777

20

No

Yes

2741.288

2.807

10

Yes

Yes

3633.721

3.720

20

Yes

Yes

3633.721

3.720

The performance numbers clearly show that increasing the connection limit to 10 offers a significant performance increase of approximately 20 percent. The results also show that increasing the connection limit beyond 10 does not offer an additional increase. This is likely due to the fact that at 10 concurrent connections a single processor client s CPU is maxed out and additional concurrent connections are bottlenecked by the CPU.

Another significant performance increase occurs when pipelining is enabled on the client. As we ve mentioned, pipelining a request results in one TCP connection being used to issue multiple requests.

Note  

Significantly poorer performance results when pipelining is enabled in Internet Information Services (IIS) 6 released with Windows Server 2003. This is a known problem that should be fixed in Service Pack 1.

Table 14-3 also shows numbers for when the Nagle algorithm is disabled. Notice that no significant performance increase is seen with Nagle disabled. This is because an HTTP GET request involves a single request being sent to the server followed by receiving the response and the data. The Nagle algorithm only affects data being sent. Disabling the Nagle algorithm will have a larger influence on HTTP POST requests. It also makes a difference whenever authentication is involved as authentication requires many more roundtrip request- responses.

Managing HTTP Verbs

Developers should be aware that the HTTP verb used can impact performance. When performing a POST operation, the server often responds with a 100 Continue after the request has been accepted. This response is typically sent to prevent the client from sending the entire request when the server rejects it. The 100 Continue logic saves network bandwidth and unneeded processing on the client side when a request is rejected; however, it can cause a bottleneck as an extra roundtrip is required to complete the POST request.

An application can explicitly override the 100 Continue behavior by using the ServicePointManager.Expect100Continue property. By default, when a POST is issued, the Framework waits 350 microseconds before the body is transmitted unless the server responds with a 100 Continue. This timeout is in place in the event that the server simply expects the client to transmit the body. With the default behavior of waiting for a 100 Continue response, a POST operation incurs two roundtrips plus a possible 350-microsecond delay before the request can complete. Setting the Expect100Continue to false would cause the body to be transmitted immediately, bypassing the 350-microsecond delay.

The GET verb can also suffer from a performance roadblock: the Nagle algorithm. A roadblock is especially likely if authentication is involved. When an application posts multiple GET requests to a server, the Nagle algorithm introduces up to a 200-microsecond delay before sending the requests. As we mentioned earlier, Nagling reduces network load by lumping more data into a single packet; this behavior can introduce significant delays, however, since HTTP GET requests tend to be smaller than the Nagle threshold and therefore incur a delay.

Authentication

Authenticating a request is a powerful and often necessary task. Of course, this process adds extra overhead to the HTTP request that can significantly affect overall performance. The .NET Framework Web classes support several authentication methods, including basic, digest, NTLM, and Kerberos. Each method incurs its own overhead for authenticating a request depending on the efficiency of the underlying protocol. Table 14-4 compares the performance of different authentication types.

Table 14-4: HTTP Authentication Performance

Authentication Type

Preauthentication

Unsafe Connection Sharing

Requests per Second

CPU Usage

None

No

No

1,322

89

Basic

No

No

1,312

90

Basic

Yes

No

962

91

Digest

No

No

219

63

Digest

Yes

No

511

60

Kerberos

No

No

1,298

59

NTLM

No

No

95

66

NTLM

No

Yes

1,261

100

The table shows the number of requests per second when using a given authentication type to retrieve a 1-KB file along with the default connection limit of two. The CPU usage on the client is also listed. Notice how enabling preauthentication increases performance for those authentication types that support it (Basic and Digest). Also notice that enabling the HttpWebRequest.UnsafeAuthenticatedConnectionSharing increases NTLM performance.

As we mentioned in Chapter 10, NTLM authentication occurs on every request as the default behavior. This can lead to server performance penalties, as illustrated by the rate of 95 connections per second shown in Table 14-4. The reason for this performance degradation is in the middle-tier scenario, where a client is making a request to a back-end server while impersonating another user . If UnsafeAuthenticatedConnectionSharing is used carelessly, then the first connection can be established using the Administrators privileges. If the client later impersonates a regular user, subsequent requests are made with Administrator rights. A way to guard against this risk when unsafe connection sharing is enabled is to use the ConnectionGroupName property to associate all requests from one user together, as shown in the following code sample:

C#

 HttpWebRequestrequest; NetworkCredentialuserJoe,userMike; request=(HttpWebRequest)WebRequest.Create(http://foo.com); userJoe=newNetworkCredential(Joe", JoePassWord!); userMike=newNetworkCredential(Mike", MikePassWord!); request.Credentials=userJoe; request.ConnectionGroupName=userJoe.UserName; request.UnsafeAuthenticatedConnectionSharing=true; //MakerequestforJoe request=(HttpWebRequest)WebRequest.Create(http://foo.com); request.Credentials=userMike; request.ConnectionGroupName=userMike.UserName; request.UnsafeAuthenticatedConnectionSharing=true; //MakerequestforMike 

Visual Basic .NET

 DimrequestAsHttpWebRequest DimuserJoeAsNetworkCredential DimuserMikeAsNetworkCredential request=WebRequest.Create("http://foo.com") userJoe=NewNetworkCredential("Joe", "JoePassWord!") userMike=NewNetworkCredential("Mike", "MikePassWord!") request.Credentials=userJoe request.ConnectionGroupName=userJoe.UserName request.UnsafeAuthenticatedConnectionSharing=True 


Network Programming for the Microsoft. NET Framework
Network Programming for the MicrosoftВ® .NET Framework (Pro-Developer)
ISBN: 073561959X
EAN: 2147483647
Year: 2003
Pages: 121

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net