This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
|
|
Paul Enfield Download the code (2KB) |
Developing a Scalable Two-tier Site with IIS |
Let me first define exactly what I mean by two-tier. The two tiers in shop.microsoft.com consist of the Microsoft®Internet Information Server (IIS) and ASP front-end code and the Microsoft SQL Serverback-end database. Shop utilizes a farm of front-end servers running IIS and a single high-performance SQL Server-based server. Using Technology as Designed
Without a business logic layer in the site design, you must decide where to place the logic necessary to build the pages. It is easy to fall into the trap of performing most operations in the IIS front-end code. When determining where code should be run, follow this simple guideline: use technologies for their designed purposes. Don't Monopolize Resources
The key to a scalable two-tier site is understanding that resources will be in demand by many browser clients at the same time. This means that finite resources such as database connections must be used in a concise manner to promote their availability. This lets your site take advantage of the performance enhancements granted by ODBC connection pooling or OLE DB session pooling. The specific methods your site utilizes depends on which data layers you use, ODBC or OLE DB. For more details on pooling see this month's Inside Knowledge column and http://msdn.microsoft.com/library/techart/pooling2.htm. |
|
The Recordset.GetRows method has a limitation in its handling of Text fields in the recordset. If there is more than one text field in your recordset, a different approach must be used. In this case, you must iterate through all the records in the recordset, moving them into the array. In Figure 2, an initial size is set for the array to hold the recordset, which is grown as necessary. This method was chosen because of the special handling necessary for TEXT columns, and for consistency and maintainability in the 1.0 version. Since that time, further performance analysis has shown that the redimensioning and looping used in this function are not optimal. In hindsight, a preferable method might have been to utilize the disconnected recordset. Better yet would be to take advantage of the SQL Server 7.0 long character fields and avoid TEXT columns wherever possible. Assuming the requirement for TEXT columns, you might rewrite this function utilizing disconnected recordsets (see Figure 3). There are a few advantages to using disconnected recordsets. As with passing arrays as the return value from the function, disconnected recordsets accomplish the goal of concise use of connections. In testing we found that disconnected recordsets performed at a virtually identical level as arrays. With the added benefit of being able to reference column data explicitly by column name, disconnected recordsets lend themselves to a more manageable piece of code. There's no need to define constants representing column indexes with disconnected recordsets. These functions demonstrate the methods for disposing of connections in a timely basis. The added benefit of this approach is that it helps work around potential problems with connection reuse. Opening a connection at the beginning of a page and utilizing it for the entire page is not only an inefficient way to use resources, but it can also lead you to these connection reuse problems. Also notice that parameters are explicitly defined by using the CreateParameter method of the Command object. This and other performance tips can be found at http://www.microsoft.com/data/impperf.htm. Use Available Data Structures
The data structures available to you have their own intrinsic benefits that should be used appropriately. Two good examples are arrays and the dictionary object. Arrays are ideally used when information needs to be stored in a group and accessed sequentially or directly. They are not ideal for storing information that must be searched. Dictionaries, however, can be good for this app. If you store information in the dictionary properly so that information you want to search for has an appropriate key value, you can reference that information in a random fashion by key name only. |
Figure 4: The shop.microsoft.com Homepage |
If you need to locate a value in an array, consider using the dictionary object. Looping through an array simply to locate an item can be a time-consuming process and can hinder scalability greatly, especially if done in a repetitive fashion. In this case, consider storing the dictionary at application scope for later use, thus avoiding the cost of repopulating
the dictionary. The VBScript scripting object dictionary is not truly a both-threaded object capable of being stored at application scope. If used this way, the object could lead to thread blocking problems. To avoid these issues, shop.microsoft.com uses the dictionary objects provided as a part of Microsoft Commerce Server 3.0. The IIS development team has also released a LookupTable object that can be used as a read-only dictionary. For details, see http://msdn.microsoft.com/workshop/management/planning/MSDNchronicles2.asp. Avoid Costly Resources
Accessing data from the database back end is frequently one of the most costly operations on a Web site. This expensive operation can sometimes be avoided by utilizing other data structures local to the machine running IIS. Shop.microsoft.com was successfully designed around application-scope dictionaries and arrays so that no database connections are incurred until a user has navigated several pages into the site. Avoid Costly Page Construction Code
Some coding conventions and structures are susceptible to eating a lot of processor time. A common culprit is large looping structures. Such a loop might construct a very large table or HTML <SELECT> box. These structures can be even more costly when nested. Pay close attention to looping structures with more than 25 iterations and evaluate possible alternative approaches. Analyze Performance Incrementally
Probably one of the biggest mistakes you can make in building a scalable site is to delay performance testing until the end of the development cycle. Performance testing should be carried out during the development cycle, and especially when considering an approach or technology that does not have a proven history. Make time to build test pages containing minimal amounts of code to compare algorithms. Conclusion
Two-tier sites are a reality of the current Web development world. With proper foresight and design, however, they can be built to perform almost as well as a full n-tier design. The design principles I've covered here led to the successful release of a scalable two-tier site, shop.microsoft.com. |
Do you have questions for FAQ? Send mail to faq@microsoft.com. |
From the October 1999 issue of Microsoft Internet Developer.