BizTalk Utilities CV ,   Jobs ,   Code library  
 
 

Washington, September 15-18, 1999 – London, November 21-24, 1999

ASP Troubleshooting and IIS Optimization Tips

Juan T Llibre

Topic Index

1.      Troubleshooting IIS Setup

2.      Troubleshooting Data Access and Scripting

3.      Script Optimization Tips

4.      Tuning IIS - Basic Performance Issues

5.      Server Optimization Tips

First things, first: let's talk about IIS setup.

Juan T. Llibre
Juan is a Microsoft Most Valuable Professional and teaches at the Universidad Nacional Pedro Henrquez Urena in the Dominican Republic. He has been developing Internet Applications for the Caribbean Common Market and the Dominican Republic's Central Bank. He is the author of the ASP resources web site www.ASPTracker.com

Troubleshooting IIS Setup

We've come a long way since Windows NT Service Pack 3 introduced IIS 3. Those of you who've been working with IIS since it was the Denali beta, know that just getting IIS properly setup –particularly after IIS4 was introduced- consisted of applying service pack 3, and then a whole slew of hotfixes.

Even after Windows NT Option Pack 4 was introduced –very shortly afterwards, in fact- we still had to apply the Quick Fix Engineering (QFE) update, plus the security hotfixes. The process is a lot simpler now: just run NTOP4…and then apply Service Pack 5.

SP5 is available at:

http://www.microsoft.com/ntserver/nts/downloads/recommended/sp5/default.asp

The list of Knowledge Base articles providing technical details on SP5 updates is at:

http://www.microsoft.com/ntserver/nts/downloads/recommended/sp5/updates.asp

The most important fixes supplied by SP5, as far as IIS is concerned, are:

Ø        Windows NT 4.0 SP4 Does Not Update MTS Files

Ø        Cannot configure ODBC logging when using Microsoft Data Access

Ø        Components (MDAC) 2.0 SP1, SP4, and Proxy Server 2.0.

Ø        Reduced heap fragmentation issues which would lead to memory problems

There is a manual fix for the ODBC logging problem: If the log file format options are not available, go to the Start menu's "Run" dialog and run

REGSVR32 iislog.dll

REGSVR32 iscomlog.dll

REGSVR32 logui.ocx

You must run all 3 commands to recover ODBC logging capability. Talking about ODBC: installation errors will occur during setup if there are any other applications or system services using the ODBC drivers on the system. If any ODBC installation errors occur, stop all desktop and system service applications, and run Setup again.

Another common setup issue occurs when Front Page 98 is installed as a separate application, particularly if you are also installing Visual InterDev 6 on the server. Visual InterDev 6 needs an updated set of Front Page Extensions, supplied on the VI6 CD. Front Page 98 installs what is now an outdated set of Extensions. The problem has been fixed by FrontPage 2000, which installs across-the-board compatible Extensions.

I'm sure –by now- that you're itching to get to specific troubleshooting and there's no better place to start than Data Access:

Troubleshooting Data Access and Scripting

Error Handling

The most important issue about troubleshooting data access is: which errors occurred?

It follows that a functional error-handling technique is vital.

Most ASP books and web sites recommend that the error-handling code you write into your applications should look something like this:

<%

If err.number <> 0 then

  Response.Write "Errors Occurred!<BR>"

  Response.Write "Error Number = " & err.number & "<BR>"

  Response.Write "Error Description = " & err.description & "<BR>"

  Response.Write "Native Error = " & err.nativeerror & "<BR>"

  Response.Write "Error Source = " & err.source & "<BR>"

  Response.Write "Please report this error to the webmaster."

End If

%>

There are a couple of problems with this code. First, most errors display this information anyway. Second, if any errors do occur, unless you're sitting at the console you may never know about it.

Here's an improved (it adds e-mail notification) error handling technique:

<!--#include virtual="/includes/ErrHandler.asp"-->

<% On Error Resume Next %>

' Your database calls go here…

<%

If Err.number <> 0 then 

  Snag Err.description

End If

  ProcErr
%>

Here's the code for ErrHandler.asp:

<%

Dim strErrMessage

Dim blnErrors

strErrMessage = ""   

blnErrors = False    

sub Snag(strError) 

blnErrors = True     

strErrMessage = strErrMessage & strError & ", "

end sub

sub ProcErr () 

if blnErrors then   

'Send an email to yourself   

  Dim objMail

  Set objMail = Server.CreateObject("CDONTS.NewMail")

      objMail.To = "yourself@yoursite.com"

      objMail.From = "yourself@yoursite.com"

      objMail.Subject = "Houston: We have a problem!"

      objMail.Body = "An error occurred at: " & Now & " on" & _

             " page " & Request.ServerVariables("SCRIPT_NAME") &_
                                chr(10) & chr(13) & "The error description is: " &  chr(10) & chr(13) & strErrMessage   
objMail.Send

Set objMail = Nothing

' Let the user know the problem has already been reported:   

Response.Write "Technical Support has been notified of this error. We are working to resolve this issue. Thank you."

end if

end sub

%>

Now, you only have to check your e-mail frequently…;>)

Option Explicit

The most common scripting error source is a misplaced variable name. By far, the best ally a VBScript programmer has, when dealing with variables, is:

<% Option Explicit %>

Using Option Explicit when you are developing, assures that all variables are declared properly.

If, for example, you write:

<%
Option Explicit

Dim x

a=Date

Response.Write a
%>

you will get back the following error message:

Microsoft VBScript runtime error '800a01f4'

Variable is undefined: 'a'

Which helps you pinpoint the source for the error. Very handy, indeed.

On the other hand, Option Explicit will slow down the VBScript engine's response, because the engine must perform checks on all the variable declarations, so be sure and remove it once you determine that your code is error-free.

Errors occurred

The most cryptic error message I've encountered is error 80040e21: "Errors occurred".

This error is usually caused by trying to insert excess data into a field that is formatted for a lesser number of characters. The resolution is to make sure the length of your data does not surpass the field length.

Type mismatch

Another fairly common error is 800a000d: "Type mismatch". You tried to insert a variant into a data-typed field, or you tried to set a variant's value to a different data type without using the appropriate conversion function. Every variable has a data type – whether they are Numeric, String, Boolean, Date, Variant or any other. The most common occurrences of this error stem from attempts to insert the result from request.querystring("variable"), request.form("variable") or request("variable") into a numeric field.

The Request object always returns a string – if you assign its value to a numeric field, you'll get this error. You must convert the variable to the appropriate data type as necessary. For example:

rs("numericfield")=CInt(request.form("something"))

rs("datefield")=CDate(request.form("something"))

This error is also caused when an attempt is made to perform arithmetic operations on alpha characters (for example, adding a string to an integer):

Response.Write strUser + 99

This VBScript error is commonly made by programmers who are more familiar with JavaScript (the + sign is used for string concatenation in JavaScript, but not in VBScript). If you want to concatenate in VBScript, use the ampersand:

Response.Write strUser & 99

Debugging SQL statements

One of the most useful tips ever handed to me is to Response.Write SQL statements before running them.

Suppose you have this SQL statement:

<%

SQLstmt = "UPDATE customer "

SQLStmt = SQLstmt & "SET username=' " & custusername & " ' , "

SQLstmt = SQLstmt & "password= ' " & custpassword & " ' "

SQLStmt = SQLStmt & " WHERE id =" & custid

%>

You can substitute fake values for the variables, and Response.Write the SQL statement to screen in order to get a visual check for missing spaces or punctuation:

<%

custusername="Joe"

custpassword="mypassword"

custid=1234

SQLstmt = "UPDATE customer "

SQLstmt = SQLstmt & "SET username='" & custusername & "',"

SQLstmt = SQLstmt & "password= '" & custpassword & "' "

SQLstmt = SQLstmt & " WHERE id =" & custid

Response.Write SQLstmt & "<p>"

%>

That would return:

UPDATE customer SET username='Joe',password= 'mypassword' WHERE id =1234

I've saved many hours of programming time with this simple technique. It's really easy to detect a missing comma or missing space that way.

Query timeout

One of the most vexing problems (though quite simple to solve) is the "Query Timeout" problem.

Generally, the problem is that the querying script times out after a minute or so. When a long-running query is run from inside SQL Server it finishes in a few minutes, so you know the query is fine, but setting the Server.ScriptTimeout and Connection.ConnectionTimeout properties to longer periods doesn't solve the problem.

…and the answer is: Set the Command.CommandTimeout property to as long a period as you need. This allows you to set the maximum time you're prepared to have ADO wait for the Command (i.e. the query) to execute. With the ConnectionTimeout property, on the other hand, you are setting the maximum time allowed for the Connection to open.

Increasing Data Access Performance

Here are some techniques that you can use to maximize your data access performance:

Ø        Cache results from data sources that seldom vary.

If you are using ADO to populate a listbox that always contains the same cities, the first call to ADO can insert the query results into an Application-scoped variable. Later requests for that listbox can then be fulfilled from the Application variable, instead of from an expensive call to a data source. You could also cache the resulting recordset client-side, by using a client-side cursor and disconnecting the recordset from the Command object.

Ø        Avoid storing ADO connections in the session object.

ODBC automatically connection pools for you, and OLE DB provides session pooling.

Ø        Use native OLE DB connection strings as much as possible.

OLE DB connection strings are generally faster than most ODBC DSN's.

Ø        Use stored procedures whenever possible.

A query executed from a stored procedure is faster than a query passed through a SQL query string.

Ø        Avoid using ADO AddNew and Delete.

You'll find that your server will perform better if it uses SQL statements, such as INSERT.

Ø        Set the ADO CacheSize property to a number larger than 1 (the default).

By forcing ADO to retrieve multiple records in one transaction with the data source, you eliminate a portion of the overhead involved in that transaction.

How To Get Useful Debugging Information

Here's a file I use regularly to get all sorts of useful debugging information:

<H1>Debug Information</H1>

<H3>Application Contents</H3>

<%

  For Each Key In Application.Contents

    Response.Write Key & " = "

    If IsObject(Application.Contents(Key)) Then

      Response.Write "<i>(object)</i>" & "<BR>"

    Else

      Response.Write Application.Contents(Key) & "<BR>"

    End If

  Next

%>

<HR>

<H3>Application Static Objects</H3>

<%

  For Each Key In Application.StaticObjects

  Response.Write Key & " = <i>(object)</i><BR>"

  Next

%>

<HR>

<H3>Request Client Certificate</H3>

<%

  For Each Key In Request.ClientCertificate

  Response.Write Key & " = " & Request.ClientCertificate(Key) & "<BR>"

  Next

%>

<HR>

<H3>Request Cookies</H3>

<%

  For Each Cookie In Request.Cookies

    If Request.Cookies(Cookie).HasKeys Then

      For Each Key In Request.Cookies(Cookie)

        Response.Write Cookie & "(" & Key & ") = " & _

          Request.Cookies(Cookie)(Key) & "<BR>"

      Next

    Else

      Response.Write Cookie & " = " & Request.Cookies(Cookie) & "<BR>"

    End If

  Next

%>

<HR>

<H3>Request Form</H3>

<%

  For Each Key In Request.Form

    Response.Write Key & " = " & Request.Form(Key) & "<BR>"

  Next

%>

<HR>

<H3>Request Query String</H3>

<%

  For Each Key In Request.QueryString

    Response.Write Key & " = " & Request.QueryString(Key) & "<BR>"

  Next

%>

<HR>

<H3>Request Server Variables</H3>

<%

  For Each Key In Request.ServerVariables

    Response.Write Key & " = " & Request.ServerVariables(Key) & "<BR>"

  Next

%>

<HR>

<H3>Session Contents</H3>

<%

For Each sessitem in Session.Contents

' Enumerate any Session Objects which cannot be displayed

If IsObject(Session.Contents(sessitem)) Then

Response.Write "Session Object <b>" & sessitem & "</b> exists but there are no contents to  display." & "<p>"

' Enumerate Arrays stored in the Session Contents Collection and display their contents

ElseIf IsArray (Session.Contents(sessitem)) Then

Response.Write "Session Array <b>" & sessitem & "</b>'s contents are:<br>"

For i=0 to UBound(Session.Contents(sessitem))

Response.Write ((Session.Contents(sessitem))(i)) & "<br>"

Next

Else

' Enumerate any other Session contents

Response.Write "Session Object <b>" & sessitem & " =</b> " & Session.Contents(sessitem) & "<BR>"

End If

Next

%>

<HR>

<H3>Session Static Objects</H3>

<%

 For Each StaticObjProp In Session.StaticObjects

 Response.Write "Session Object = <b>" & StaticObjProp & "</b><BR><hr><br>"

 Next

%>

<p>

<%
' Check for Component Availability

dim successSTR, FailSTR,checkSTR

whichfile=server.mappath("component.ini")

Set fs = CreateObject("Scripting.FileSystemObject")

Set thisfile = fs.OpenTextFile(whichfile, 1, False)

counter=0

do UNTIL thisfile.AtEndOfStream

  counter=counter+1

  thisline=thisfile.readline

              attempt=thisline

  If mid(thisline,1,1)="[" then

  ' ignore

  CheckSTR=CheckSTR & thisline & " "

  category=thisline

  thisline=thisfile.readline

  attempt=thisline

  end if

  on  error resume next

  set tempobject=server.createobject(attempt)

  If err.number=0 then

  successSTR = successSTR & "<b>" &  attempt & "</b> is available.<br>"

  else

  FailSTR=FailSTR & category & " <b>" &  attempt & "</b> failed. Error #" & err.number & "<br>"

  end if

  set tempobject=nothing

loop

thisfile.Close

set thisfile=nothing

set fs=nothing

Response.Write "<center><h2>Components Available:</h2> </center>"

Response.Write successSTR & "<hr><br>"

Response.Write failSTR

Response.Write "<center><h2>Database Connectivity Check:</h2> </center>"

Response.Write "<hr><br>"

set tempconn=server.createobject("adodb.connection")

Dim strCnn

StrCnn="driver={SQL Server};server=(local);uid=internetuser;pwd=internetuser;database=SessionSQL"

tempconn.Open strCnn        

Response.Write "ADO Version = <b>"

Response.Write tempconn.version & "</b><br>"

Response.Write"ADO Provider = <b>" &  tempconn.provider & "</b><br>"

strVersionInfo = "DBMS Name: <b>" & tempconn.Properties("DBMS Name") & "</b><br>" & _

  "DBMS Version: <b>" & tempconn.Properties("DBMS Version") & "</b><br>" & _

  "OLE DB Version: <b>" & tempconn.Properties("OLE DB Version") & "</b><br>" & _

  "Provider Version: <b>" & tempconn.Properties("Provider Version") & "</b><br>" & _

  "Driver File: <b>" & tempconn.Properties("Driver Name") & "</b><br>" & _

  "Driver File Version: <b>" & tempconn.Properties("Driver Version") & "</b><br>" & _

  "ODBC Driver Version: <b> " & tempconn.Properties("Driver ODBC Version") & "</b>"

Response.Write strVersionInfo & "<br>"

tempconn.close

Response.Write "<hr><br>"

Response.Write "<center><h2>Other Useful Info:</h2> </center>"

Response.Write "<hr><br>"

Response.Write "Script Timeout = <b>" & Server.ScriptTimeout & " seconds.</b><br>"

Response.Write "Session Timeout = <b>" & Session.Timeout & " minutes.</b><hr><p>"

 %>

In one fell swoop, this file gives you: Application Objects, Application Static Objects, Session Objects, Session Static Objects, Database Connectivity Information, Server Variables, Available Components, Client Certificates instantiated, Live Cookies, Request Object Contents, and TimeOut values. Very handy, indeed…

I am indebted to Charles Carroll, a well-known ASP guru, for the Component Availability check.

It needs this .ini file:

component.ini:

------------------

[standard]

mswc.browsertype

mswc.nextlink

scripting.dictionary

scripting.filesystemobject

[ado]

adodb.recordset

adodb.connection

adodb.command

[msfreebies]

iissample.asp2htm

iissample.contentrotator

IISSample.RegistryAccess

iissample.summaryinfos

iissample.tracer

mswc.adrotator

mswc.counters

mswc.myinfo

MSWC.PermissionChecker

mswc.tools

InetCtls.Inet.1

[serverobjects]

AspHTTP.Conn

[llibre]

llibre.http

[other]

BinObj.BinRead

------------------------

You can customize "component.ini" by including any custom object references that you'd like to test.

Script Optimization Tips

1.      Never use the Dictionary Object in global.asa.

Use the Lookup Table Object, instead.

The Lookup Table Object avoids threading problems associated with Application-scoped or Session-scoped dictionaries. The Dictionary object is apartment-threaded, even though when it was introduced developers were told that it was safe to mark it as both-threaded. It is NOT safe to do so, and if the dictionary object is marked as both-threaded, you'll end up with data corruption. All requests for the Dictionary object are locked down to the thread on which the object was first called and every other request has to wait in line to be executed, which you'll find will slow down your server quite a bit.

Download it at: http://msdn.microsoft.com/workshop/server/downloads/lkuptbl_eula.asp

Basic Info at: http://msdn.microsoft.com/msdn-online/MSDNchronicles2.asp

2.     Response.Write all your HTML.

When you alternate between HTML and script code, the server's response time is slowed down because two different dll's will write to the html stream being returned to the client. Let me show you a simple example:

<html>

<head>

<title>Test</title>

</head>

<body>

<%=date %>

</body>

</html>

…will always be slower than:

<%

Response.Write "<html>" & VbCrLf

Response.Write "<head>" & VbCrLf

Response.Write "<title>Test</title>" & VbCrLf

Response.Write "</head>" & VbCrLf

Response.Write "<body>" & VbCrLf

Response.Write date & VbCrLf

Response.Write "</body>" & VbCrLf

Response.Write "</html>" & VbCrLf

%>

This is just a simple example. The more you alternate between script and HTML, the slower your server will perform.

3.     Use Local Variables

Using local variables may save you a few server cpu cycles. Here's an example:

a.b.c.d = a.b.c.e

If a.b.c.f = a.b.c.g then

' …rest of code

This is terribly inefficient. Let's see what actually happens when that code runs:

"a" is resolved as a global object

"b" is resolved as a property of "a"

"c" is resolved as a property of "a.b"

"d" is resolved as a property of "a.b.c"

"a.b.c.e" is now resolved, which means that:

"a" has to be resolved again as a global object

"b" has to be resolved again as a property of "a"

"c" has to be resolved again as a property of "a.b"

"e" is resolved as a property of "a.b.c"

Now we have to resolve "a.b.c.f", so:

"a" has to be resolved again as a global object

"b" has to be resolved again as a property of "a"

"c" has to be resolved again as a property of "a.b"

"f" is resolved as a property of "a.b.c"

Now we have to resolve "a.b.c.g", so:

"a" has to be resolved again as a global object

"b" has to be resolved again as a property of "a"

"c" has to be resolved again as a property of "a.b"

"g" is resolved as a property of "a.b.c"

Compare this to:

Set Obj = a.b.c            ' resolve "a.b.c" ONCE

Obj.d = Obj.e              ' the value is obtained instantly, since "a.b.c" is already resolved

If Obj.f = Obj.g then    ' the values are obtained instantly, since "a.b.c" is already resolved

' …rest of code

Neat, isn't it?

Storing server-side variables as local variables will significantly speed up your pages. This is particularly applicable to recordset values and anything retrieved from the request object.

i.e., instead of:

<%

If rs ("name")="Juan" Then

   ' do something

End If

If rs ("name")="Joe" Then

   ' do something

End If

If rs("name")="Bill" Then

   ' do something

End If

%>

Use:

<%

name= rs("name")

If name="Juan" Then

   ' do something

End If

If name="Joe" Then

   ' do something

End If

If name="Bill" Then

   ' do something

End If

%>

The same applies to values retrieved from the Request Object:

Instead of:

<%

If Request.Form("name")="Juan" Then

   ' do something

End If

If Request.Form("name")="Joe" Then

   ' do something

End If

If Request.Form("name")="Bill" Then

   ' do something

End If

%>

Use:

<%
name=Request.Form("name")

If name="Juan" Then

   ' do something

End If

If name="Joe" Then

   ' do something

End If

If name="Bill" Then

   ' do something

End If

%>

The same applies to Request.QueryString("somevalue")

4.     Use Literal Paths

When you use Server.MapPath, the path is retrieved via a separate request. That takes time.

Paths such as "c:\data\app\myfile.ext" will always be resolved faster than Server.MapPath "/app/myfile.ext".

5.     Validate client-side whenever possible.

Server-side validation overloads your server. Think about what is really happening when your server is validating 100 simultaneous requests. Now think of the processor time saved when each client does its own validation.

6.     Use as few server variables as possible.

The tendency when we start programming ASP is to store everything in server variables, so we can have fast access to the variables' values…should we need them. Don't ! This is especially critical when you store data in server objects, like recordset objects or arrays.

7.     Use Application variables instead of Session variables where appropiate, or use include files.

This is particularly applicable to database connections. I constantly see database connections being stored in Session variables. If you use a Session variable to store connection information, every user who hits your site will eat up some ram. If you use an Application variable to store your connection information, only ONE variable is handling ALL of your users' connection information. Much cheaper…

So, in global.asa, instead of:

Session_OnStart

   Session("conn")="DSN=clients;"

   Session("user")="someone"

   Session("pass")="yourpassword"

End Sub

and in your scripts, using:

set cn=Server.CreateObject("ADODB.Connection")

cn.open Session("conn") & "uid=" & Session("user") & ";pwd=" & Session("pass")

Use:

Application_OnStart

  Application("conn")="DSN=clients;"

  Application("user")="someone"

  Application("pass")="yourpassword"

End Sub

and in your scripts, use:

set cn=Server.CreateObject("ADODB.Connection")

cn.open Application("conn") & "uid=" & Application("user") & ";pwd=" & Application("pass")

Alternately, you could use an include file:

conn.asp:

<%

conn="DSN=clients;"

user="someone"

pass="yourpassword"

%>

and in your scripts:

<!--#include virtual="/includes/conn.asp"-->

set cn=Server.CreateObject("ADODB.Connection")

cn.open conn & "uid=" & user & ";pwd=" & pass

Using Application variables or include files will cost you less processing power than using Session variables.

8.     Don't redim arrays.

It is quicker to just create a new, larger, array than to redim an old one.

IIS Optimization

Basic Optimization Issues

Every web programmer's dream is to build the perfect website. We picture ourselves as authors of the most popular site on the Internet. Millions of hits daily. Yeah!

So, we create our site, and watch the visitor numbers shoot up, and -just when we're really feeling good- on one of our site checks we get a "Server is too Busy" message: "403.9 Access Forbidden: Too many users are connected." Either you set a maximum number of users, or you don't have enough server load capability.

If you did not set a maximum number of users (something you can do as an interim measure to prevent overloading your server…) then either you don't have enough processor capacity, RAM or other server resources, or your scripts unnecessarily overload your server.

What can you do about this? Let's start by defining a few terms:

Processor load

Every request sent to your website entails an added task for your server's processor. If the load (the number of tasks requested) is too large for your processing capacity, the server will get bogged down. Make sure your processor is fast enough for the maximum number of tasks that you expect to be requested. You might have to consider multiprocessor servers –or server "web farms"- in order to handle large request loads.

Memory Usage

RAM…RAM…and then more RAM. IIS needs a LOT of RAM, and RAM is so cheap these days that it's just inexcusable to setup a server with insufficient RAM for the load it's supposed to carry.

Other Server Resources

You need enough bandwidth in order to have an efficient web server. You also need enough hard disk space. A congested, fragmented, hard drive will slow down your server.

Scripting Load

Be ultra-careful about loading data in Session objects. A friend of mine complained to me about how sluggish his server was and, when I looked at his global.asa, I noticed that he loaded a 10MB recordset object in the Session object (supposedly so that users would have fast access to it). When I explained to him that, if 100 users connected simultaneously to his site, he'd need a Gygabyte of ram just for that recordset object, he was truly surprised.

Testing for Enough Server Capacity

OK, so you have enough processing capacity, enough RAM, enough bandwidth, 20GB of unused, unfragmented disk space, and you are not storing dinosaurs in the Session object. What now? Performance testing, of course.

WCAT: A Tool to Test IIS Server and Client Capacity

WCAT (Microsoft Web Capacity Analysis Tool ) runs simulated workloads on client-server configurations. Using WCAT, you can test how your IIS and network configuration respond to repeated client requests for content, data, or HTML pages. You can use the results of these tests to determine your optimal server and network configurations.

WCAT is available at: http://msdn.microsoft.com/workshop/server/toolbox/wcat.asp

And you can download it from: http://msdn.microsoft.com/workshop/server/toolbox/WCATx86.exe

WCAT includes more than 40 ready-to-run tests. You can also design and run your own.

There's complete instructions at the first URL, so I will not bother you with the details. Just go there.

…and also go to: http://msdn.microsoft.com/workshop/server/iis/usingWCAT.asp

where you'll learn everything you want to know about using WCAT to stress-test IIS.

Then there's InetLoad 2.0.

InetLoad is an advanced load generation tool for IIS. It's designed to address multiple Internet protocols and varying user profiles, and has an easy to use interface. It supports the HTTP, NNTP, SMTP, POP3, IRC, and LDAP protocols, and you can setup a mix of any of these. By scripting the behavior of users, InetLoad can simulate almost any client profile including authentication schemes such as Basic and NTLM.

InetLoad has high performance testing capabilities. Depending on the protocol and the user profile, InetLoad can simulate thousands of active, simultaneous, users per server.

InetLoad is available at: http://www.microsoft.com/msdownload/inetload/inetload.htm

Download it…and learn how to use it.

And, of course, there's Performance Monitor, included with Windows NT.

Monitoring your web server is vital both for capacity planning and troubleshooting and tuning.

We could spend several days dissecting each Performance Monitor counter, so we won't! Suffice it to say that you should set up a log that covers the basic objects: Processor, Memory, Disk, Network, IIS Global, Web service, and Active Server Pages. Then, let it run for at least a week, making sure your polling interval does not take up too much of your available processing capacity or disk space (Those logs tend to be a bit on the long side)…and analyze it. You may be surprised at what you learn!

Server Optimization

General Tuning Parameters

1.      Set Windows NT Server to AppServer

Right-click Network Neighborhood and select Properties. On the Services tab, double-click the Server service. Select Network Applications.

2.      Remove irrelevant script mappings

Open the IIS snap-in. Right-click Default Web Site and select properties. Select the Home Directory property sheet. Click the Configuration button under the Application Settings section. Remove all unused mappings, leaving at least one active mapping (the server requires at least one mapping).

3.      Set the proper Performance Level for your site.

Open the IIS snap-in. Right-click Default Web Site and select Properties. Select the Performance property sheet. Move the slider bar to the desired setting.

4.      Disable performance boost for foreground applications.

Open Control Panel. Double-click the System icon, and select the Performance property sheet. Move the Application Performance slider to "None".

5.      Disable logging when it's not needed any more.

Open the IIS snap-in. Right-click Default Web Site and select Properties. Open the Web Site property page, and uncheck Enable Logging. Click OK.

Tuning the IIS Thread Pool and the ASP Request Queue.

Serving information which depends on servers other than the one where IIS is setup needs special tuning parameters in order to achieve high volume capacity.

IIS serves non-blocking files (files which are served faster than the rate they are requested at) at a very fast rate. .htm files are served very fast, too, but when IIS is not able to keep up with the pace at which files get requested, the files are placed in a Queue.

Queueing is particularly heavy when IIS is servicing ASP Server.CreateObject requests.

When queueing/blocking occurs, requests are placed in the IIS ASP Request queue and are processed in the order in which they are received. When the request spikes last for a long enough period of time, the queue builds up and peaks at the IIS registry value for RequestQueueMax, (default: 500). When the queue reaches that registry value, IIS returns a "Server Too Busy" message.

There are two Registry settings which can have a significant impact on the performance and queueing of your site: ProcessorThreadMax and RequestQueueMax.

ProcessorThreadMax is the maximum threads per processor.

RequestQueueMax is the maximum size of the request queue.

These registry settings are at:

HKEY_LOCAL_MACHINE\

SYSTEM\

CurrentControlSet\

Services\

W3SVC\

ASP\

Parameters

The goal for ProcessorThreadMax is to get processor utilization at around seventy percent during peak load times.

Use Performance Monitor to check up on:

Processor: %Processor Time

ActiveServerPages: Requests/Sec, Requests Rejected, Total Queue Length

HttpService: Connections/Second, Current Anonymous Users

If the Total Queue Length doesn't go up and you are running at low processor utilization, this indicates that you have more installed capacity than you need. If your Queue is going up and down and your processors are running below fifty percent, some of your requests are blocking. You can benefit by increasing your threads.

To increase your server's performance, start by doubling the number of threads: Change ProcessorThreadMax from 10 (default) to 20.

You should see some increase in processor utilization and the queue will tend to go up and down more quickly. Increasing the number of threads improves overall response time.

If your queue stays down and processor utilization increases, continue increasing ProcessorThreadMax until your Processor Time is below seventy percent at peak times (but keep ProcessorThreadMax below 40).

Tuning RequestQueueMax ensures good response time while minimizing "Server Too Busy" states.

You need to determine your target response time (5-10 seconds ?) and keep the Total Queue Length under that. The ideal queue size is: below your response time target, but above your peak load queue size. Too small a queue size will net you too many "Server Too Busy" errors. Too large a queue size, and the site will look hung and users will go somewhere else.

Tips To Minimize Queueing:

Ø        Use .HTM files. They never block.

Ø        Minimize the use of Server.CreateObject as much as possible.

Ø        Minimize external data calls to a SQL Server not on the same machine as IIS.

Ø        Maximize network performance.

Ø        Load test all custom objects before deploying them.

Ø        Make sure that any component used executes faster than the rate at which it's called. If a component is called 10 times per second, it must completely execute in less than 1/10 of a second or it will block.

Ø        A single blocking component can slow down all ASP scripts on your site.

Well, that’s it for today.
I have no final parting words of wisdom.
Thank you for coming...and listening.

 

Recent Jobs

Integration Specialist Needed - Wor
Virtualization Server Infrastructur
A great opportunity to Digital Vide
here is a greate opportunity as a S
A great opportunity as a Network En

View all Jobs (Add yours)
View all CV (Add yours)



Information Online

swimming pool contractor
chicago web site design
service internet fax
Web Hosting
fax server
Bvlgari sunglasses
answering service


    Email TopXML  

Front Page Daily Stuff TopXML Forum XML blogs XML Newsgroups BizTalk Biztalk Utilities Biztalk Utilities Tutorial B2B SAP XML Microsoft .NET Dotnet System XML Soapformatter SQLXML XMLserializer XQuery PHP PHP SimpleXML PHP XML Dom PHP XML RPC PHP XSLT Java Java Java XML Xalan Microsoft ASP ASP Schemas XML SQL Server XML XMLDom XSL XSL Tutorial XSLT Stylesheets General Javascript CSS XHTML WAP