Squeeze every drop of performance out of your IIS 5.0 or IIS 4.0 system

Web server configurations depend on multiple factors such as CPU speed, number of CPUs, amount of memory and disk space, type of network cards, and hardware manufacturers. If you choose unwisely regarding any of these components, the server's performance will most likely be subpar. The most important and most talked about item on the list is memory. Let's dig into the subject of how much memory an IIS system needs, how IIS uses memory, and how you can tweak IIS to make it use memory more efficiently. The following discussion applies to both IIS 5.0 and IIS 4.0.

How Much Is Enough?
When the topic of memory comes up, the first question usually is, "How much is enough?" A basic IIS implementation serving static Web pages to a few users might require no memory beyond what Windows 2000 or Windows NT 4.0 requires. An IIS system serving active content to thousands of users will probably require quite a bit more memory. I can't give you one answer to the "How much is enough?" question, but I can give you some insight into how IIS uses memory.

In early 2000, CN2 Technology tested an IIS 5.0 application in four scenarios: using low-level Internet Server API (ISAPI) code, using C++ COM components, using Visual Basic (VB) COM components, and using Active Server Pages (ASP) script with no custom components. The ISAPI files, COM components, and ASP script ran on Win2K Advanced Server with Network Load Balancing (NLB). The database ran on a separate server. You can see a description of the test application that CN2 Technology used at http://msdn.microsoft.com/library/backgrnd/html/nilewp.htm.

In CN2 Technology's tests, the IIS 5.0 servers were insensitive to the amount of memory in the system. During the first set of tests, each IIS server in the NLB cluster had 256MB of memory. Then, CN2 Technology took the servers down to 128MB and reran the tests. The tests showed little performance degradation. Of course, these servers were running only one application. A server running two or more applications will place more, or at least different, memory demands on the system. Also, the servers were running in an NLB cluster, so each server was supporting fewer users than if only one server had been used. You might conclude from the CN2 Technology tests that if your servers are running only IIS 5.0 and COM+ components, they might not need more than 256MB of memory, at least to begin with.

What does IIS use that memory for? IIS 5.0 and IIS 4.0 both use the Inetinfo process as the main IIS process. The Microsoft Internet Information Services 5.0 Resource Guide mentions that Inetinfo consumes about 2.5MB of memory when all services are running. IIS 4.0 Inetinfo consumes about 2MB of memory. Of course, these numbers assume the default IIS settings and that no ASP code is running and no other activities are going on.

According to the IIS 5.0 resource guide, each connection to IIS 5.0 uses about 10KB of memory, and the same is likely true for IIS 4.0. Thus, 500 connections would add 5MB and 1000 connections would add 10MB to the amount of memory used. When you think about the number of connections you have, remember that one user usually has multiple connections. For example, 1000 simultaneous users will usually translate into more than 1000 connections.

In addition, IIS increases the size of the Inetinfo process for various reasons, such as log files. If you turn on logging for a Web site, IIS maps a chunk of memory (in 64KB blocks) as the site's log file. A memory-mapped log file provides fast access to the file system. However, if, for example, you enable logging for each of the 10 Web sites on your server, IIS is setting aside quite a bit of memory for log files.

IIS also increases the size of the Inetinfo process to accommodate applications running in that process. You can run IIS 5.0 and IIS 4.0 applications in the Inetinfo process or out of the process. Applications that run in process typically perform better than those that run out of process, but if an application running in process crashes, it can take IIS down with it.

In IIS 4.0, each application that runs out of process runs in its own Mtx process. In IIS 5.0, each application that runs out of process runs in its own Dllhost process. IIS 5.0 has an additional processing option: Multiple applications can run together in a pooled Dllhost process. According to Microsoft, pooled applications perform better than out-of-process applications but not as well as in-process applications. By default, IIS 4.0 applications run in process and IIS 5.0 applications run out of process. For more information about IIS 5.0's three process options, see my Windows 2000 Magazine article "IIS 5.0 Opens the Throttle" (Winter 2000).

You can use Windows Task Manager to discover how much memory Inetinfo and Dllhost or Mtx are using. Figure 1 shows two Dllhost processes (i.e., dllhost.exe) running on an IIS 5.0 system. The first Dllhost entry is an out-of-process application. The second Dllhost process is the pooled process on the server and represents the entire pool's memory usage: 7972KB. You can also see that the Inetinfo process on this system is using 14,236KB of memory.

I know of several sites that have experienced a memory problem when running applications out of process in IIS 4.0. The symptoms are clear: The application gradually slows down to the point at which it's unusable. Rebooting the NT 4.0 server solves the problem for a while, but then the application slows down again. IIS 4.0 application slowdowns are a result of poorly coded applications or problems with IIS 4.0. Apply application and OS fixes and service packs, and where possible, change out of process IIS 4.0 applications to run in process. I'm not aware of similar slowdowns with out of process or pooled applications in IIS 5.0, although as I pointed out earlier, Microsoft says applications will run faster in process.

To answer the question of how much memory is enough for your IIS server, be prepared for some ongoing trial and error. Each server (or set of servers in a farm) has a different set of applications and a different configuration. Thus, each server will require a different amount of memory. You can start with a known amount such as 128MB or 256MB, then test your servers to find out how much to add. You must also monitor the servers over time to keep up with changes to their configuration, the applications running on them, and their load.

IIS and Server Properties That Affect Memory
Before you add memory to an IIS server to alleviate a performance problem, you should make sure a few key configuration options are set properly for your situation. The script-engine cache, which contains ready-to-run script engines, consumes a small amount of memory. When IIS receives a request for an .asp file, it can access a script engine from the cache rather than starting one from disk. This results in much faster performance for .asp files. IIS 5.0 and IIS 4.0 default to 30 cached script engines. You can change this property as needed on the Process Options tab, which Figure 2 shows. To access this tab in IIS 5.0, open Internet Services Manager (ISM), select WWW Service, click Edit, and click Home Directory. In the Application Settings section, click Configuration, and click the Process Options tab.

Another memory user is the IIS script-file cache, which holds templates (compiled .asp files with all their included files). When IIS receives a request for an .asp file, it looks first in the script-file cache. If the file isn't in the cache, IIS reads the file from disk, processes the file, and places it in the cache. The time to process and cache a file ranges from much less than 1 second to many seconds, depending on the length of the script and how busy IIS is when it receives the request. IIS can take as long as 20 seconds to load large .asp files from disk (a large .asp file with 8 to 10 included files can have 3000 or more lines of code), whereas IIS could load those files from the cache in less than 1 second.

If you don't correctly size the script-file cache property, your application performance will suffer. IIS 4.0 is set to cache all .asp files by default, which lets the cache grow arbitrarily large and potentially use all of a server's memory as cache. IIS 5.0 defaults the cache to 256 files to prevent excessive growth. For both IIS 5.0 and IIS 4.0, you can use the Process Options property page that Figure 2 shows to change the maximum number of .asp files to be cached.

Don't set the cache property to a very low number because that will probably cause IIS to spend much more time reading .asp files from disk. Also, don't set the property to cache all files because that might consume more memory than is necessary. You might use 256 as a starting point, keeping in mind that you might need to adjust the number depending on factors such as the size and number of .asp files you're using and the amount of memory in the server.

You can also ask developers to place common code in COM components to minimize the amount of script that must be cached. The fewer lines of script, the faster IIS can read the page and cache it. Common code placed in a COM object is easier to use and scales more effectively than a script, thereby making your server easier to maintain. However, you must recompile the component containing the COM object when you want to make changes.

IIS's Performance Tuning also affects how much memory IIS uses. You can use the Performance tab of the Web site Properties page to adjust the memory that IIS 5.0 or IIS 4.0 uses to handle the Web site's connections and resources. Drag the Performance Tuning slider to the setting just higher than the number of hits you expect to receive in a day. For example, if you expect to get 95,000 hits per day, set the slider at Fewer than 100,000. (The slider moves to only three positions, so you need only an approximate idea of the number of hits.) A higher setting allocates more memory for connections, so IIS can use more memory to make connections faster. But a setting too much higher than the number of actual hits causes IIS to waste memory.

You should also set a Win2K or NT 4.0 networking property to maximize data throughput for file and printer sharing so that IIS can use more memory for Web and other network applications. To change the property, open Network and Dial-up Connections, select the connection you want to change, select File and Printer Sharing for Microsoft Networks, and open its properties. On the Server Optimization tab, select Maximize data throughput for network applications, then click OK.

Session and Application Variables
You can also affect IIS memory usage and performance through the way you administer the server and the way your developers use Session and Application variables. IIS 3.0 and later include a session-state feature as part of the ASP Session object. If you turn on session support for an application (support is on by default in IIS 5.0 and IIS 4.0), the Session object lets an application store data in discrete, user-definable variables. The application can then access the data in these variables later on.

For example, the following code can store a customer ID in a Session variable:

Session("CustID") = 1234

Later, the application can use the following statement to retrieve the customer number:

SCustID = Session("CustID")

Applications can store anything in a Session variable because all VBScript variables are variants (i.e., variables that take any type of data). If an application stores data in a Session variable that requires 5 bytes of memory and the site has 1000 simultaneous users, the application is using 5000 bytes, or roughly 5KB, of memory. That's not bad. But what if another application uses another variable to store the contents of a database table or a file and this variable requires 512KB of memory. Multiply this by 1000 users, and you find that the application is using roughly 520MB of memory. You might think that a developer would never store that much data in a Session variable, but I've seen almost anything you can imagine stored in Session variables, including very large amounts of data. The problem is further compounded because IIS must track the use of Session variables by user (i.e., by sessionid)—a requirement that adds to the server's memory overhead and adds processing for IIS.

The solution is to ask your developers to create or modify their applications so that they don't require Session objects, then turn off session support for the applications. Instead of using Session variables, developers can store variable data in a fast database, such as Microsoft SQL Server, or use another technique.

To turn off session support for an IIS 5.0 or IIS 4.0 application, open the application's properties in ISM, click the App Options tab, clear the Enable session state check box, and click OK to close the page and update the metabase. After you make this change, the application will no longer support session state and its memory requirements should decrease. The amount of memory reduction will vary depending on how much information the Session object was storing. You can also turn off support for Session variables at the page level or for the entire Web server.

Developers can use the Application object to store information that's the same for all users of an application and that all application users can access. For example, the statement

Application("States") = StateList

creates an Application variable and stores the contents of the StateList variable (an array of state names) in the States variable. If the list of states consumes 100 bytes, storing the list in the Application object consumes 100 bytes (not 100 bytes per user as with the Session object).

You should consider storing data such as short, unchanging lists in Application variables. Data in an Application variable resides in memory, where the system can access the data more quickly than it could if the data were on disk. Because an Application variable stores data only once per application per server, Application variables have minimal impact on a server's memory usage.

Memory Management
I can't delineate one configuration that will work for all IIS servers. The amount of memory that your IIS servers consume will vary depending on the ASP applications running on the servers. Both Web administrators and Web developers must understand how IIS uses memory. Administrators must configure servers to optimize the available memory, and developers must design applications to make the most effective use of memory (e.g., by avoiding Session variables). In addition, you must test and monitor your applications to make sure both they and the servers are behaving properly.

If an IIS server's performance degrades over time, you might need to add memory or processors to the server. The server also might benefit from multiple network cards or larger and faster disks. You also might find that you can improve performance by moving certain application features to another server.