Bump versions for dev release pending
[catagits/fcgi2.git] / doc / fcgi-perf.htm
index ec916e9..bf697c9 100644 (file)
-<html>
-<head><title>Understanding FastCGI Application Performance</title>
-</head>
-
-<body bgcolor="#FFFFFF" text="#000000" link="#cc0000" alink="#000011" 
-vlink="#555555">
-
-<center>
-<a href="/fastcgi/words">
-    <img border=0 src="../images/fcgi-hd.gif" alt="[[FastCGI]]"></a>
-</center>
-<br clear=all>
-<h3><center>Understanding FastCGI Application Performance</center></h3>
-
-<!--Copyright (c) 1996 Open Market, Inc.                                    -->
-<!--See the file "LICENSE.TERMS" for information on usage and redistribution-->
-<!--of this file, and for a DISCLAIMER OF ALL WARRANTIES.                   -->
-
-<center>
-Mark R. Brown<br>
-Open Market, Inc.<br>
-<p>
-
-10 June 1996<br>
-</center>
-<p>
-
-<h5 align=center>
-Copyright &copy; 1996 Open Market, Inc.  245 First Street, Cambridge,
-  MA 02142 U.S.A.<br>
-Tel: 617-621-9500 Fax: 617-621-1703 URL:
-  <a href="http://www.openmarket.com/">http://www.openmarket.com/</a><br>
-$Id: fcgi-perf.htm,v 1.1 1997/09/16 15:36:26 stanleyg Exp $ <br>
-</h5>
-<hr>
-
-<ul type=square>
-    <li><a HREF = "#S1">1. Introduction</a>
-    <li><a HREF = "#S2">2. Performance Basics</a>
-    <li><a HREF = "#S3">3. Caching</a>
-    <li><a HREF = "#S4">4. Database Access</a>
-    <li><a HREF = "#S5">5. A Performance Test</a>
-    <ul type=square>
-        <li><a HREF = "#S5.1">5.1 Application Scenario</a>
-        <li><a HREF = "#S5.2">5.2 Application Design</a>
-        <li><a HREF = "#S5.3">5.3 Test Conditions</a>
-        <li><a HREF = "#S5.4">5.4 Test Results and Discussion</a>
-    </ul>
-    <li><a HREF = "#S6">6. Multi-threaded APIs</a>
-    <li><a HREF = "#S7">7. Conclusion</a>
-</ul>
-<p>
-
-<hr>
-
-
-<h3><a name = "S1">1. Introduction</a></h3>
-
-
-Just how fast is FastCGI?  How does the performance of a FastCGI
-application compare with the performance of the same
-application implemented using a Web server API?<p>
-
-Of course, the answer is that it depends upon the application.
-A more complete answer is that FastCGI often wins by a significant
-margin, and seldom loses by very much.<p>
-
-Papers on computer system performance can be laden with complex graphs
-showing how this varies with that.  Seldom do the graphs shed much
-light on <i>why</i> one system is faster than another.  Advertising copy is
-often even less informative.  An ad from one large Web server vendor
-says that its server "executes web applications up to five times
-faster than all other servers," but the ad gives little clue where the
-number "five" came from.<p>
-
-This paper is meant to convey an understanding of the primary factors
-that influence the performance of Web server applications and to show
-that architectural differences between FastCGI and server APIs often
-give an "unfair" performance advantage to FastCGI applications.  We
-run a test that shows a FastCGI application running three times faster
-than the corresponding Web server API application.  Under different
-conditions this factor might be larger or smaller.  We show you what
-you'd need to measure to figure that out for the situation you face,
-rather than just saying "we're three times faster" and moving on.<p>
-
-This paper makes no attempt to prove that FastCGI is better than Web
-server APIs for every application.  Web server APIs enable lightweight
-protocol extensions, such as Open Market's SecureLink extension, to be
-added to Web servers, as well as allowing other forms of server
-customization.  But APIs are not well matched to mainstream applications
-such as personalized content or access to corporate databases, because
-of API drawbacks including high complexity, low security, and
-limited scalability.  FastCGI shines when used for the vast
-majority of Web applications.<p>
-
-
-
-<h3><a name = "S2">2. Performance Basics</a></h3>
-
-
-Since this paper is about performance we need to be clear on
-what "performance" is.<p>
-
-The standard way to measure performance in a request-response system
-like the Web is to measure peak request throughput subject to a
-response time constriaint.  For instance, a Web server application
-might be capable of performing 20 requests per second while responding
-to 90% of the requests in less than 2 seconds.<p>
-
-Response time is a thorny thing to measure on the Web because client
-communications links to the Internet have widely varying bandwidth.
-If the client is slow to read the server's response, response time at
-both the client and the server will go up, and there's nothing the
-server can do about it.  For the purposes of making repeatable
-measurements the client should have a high-bandwidth communications
-link to the server.<p>
-
-[Footnote: When designing a Web server application that will be
-accessed over slow (e.g. 14.4 or even 28.8 kilobit/second modem)
-channels, pay attention to the simultaneous connections bottleneck.
-Some servers are limited by design to only 100 or 200 simultaneous
-connections.  If your application sends 50 kilobytes of data to a
-typical client that can read 2 kilobytes per second, then a request
-takes 25 seconds to complete.  If your server is limited to 100
-simultaneous connections, throughput is limited to just 4 requests per
-second.]<p>
-
-Response time is seldom an issue when load is light, but response
-times rise quickly as the system approaches a bottleneck on some
-limited resource.  The three resources that typical systems run out of
-are network I/O, disk I/O, and processor time.  If short response time
-is a goal, it is a good idea to stay at or below 50% load on each of
-these resources.  For instance, if your disk subsystem is capable of
-delivering 200 I/Os per second, then try to run your application at
-100 I/Os per second to avoid having the disk subsystem contribute to
-slow response times.  Through careful management it is possible to
-succeed in running closer to the edge, but careful management is both
-difficult and expensive so few systems get it.<p>
-
-If a Web server application is local to the Web server machine, then
-its internal design has no impact on network I/O.  Application design
-can have a big impact on usage of disk I/O and processor time.<p>
-
-
-
-<h3><a name = "S3">3. Caching</a></h3>
-
-
-It is a rare Web server application that doesn't run fast when all the
-information it needs is available in its memory.  And if the
-application doesn't run fast under those conditions, the possible
-solutions are evident: Tune the processor-hungry parts of the
-application, install a faster processor, or change the application's
-functional specification so it doesn't need to do so much work.<p>
-
-The way to make information available in memory is by caching.  A
-cache is an in-memory data structure that contains information that's
-been read from its permanent home on disk.  When the application needs
-information, it consults the cache, and uses the information if it is
-there.  Otherwise is reads the information from disk and places a copy
-in the cache.  If the cache is full, the application discards some old
-information before adding the new.  When the application needs to
-change cached information, it changes both the cache entry and the
-information on disk.  That way, if the application crashes, no
-information is lost; the application just runs more slowly for awhile
-after restarting, because the cache doesn't improve performance
-when it is empty.<p>
-
-Caching can reduce both disk I/O and processor time, because reading
-information from disk uses more processor time than reading it from
-the cache.  Because caching addresses both of the potential
-bottlenecks, it is the focal point of high-performance Web server
-application design.  CGI applications couldn't perform in-memory
-caching, because they exited after processing just one request.  Web
-server APIs promised to solve this problem.  But how effective is the
-solution?<p>
-
-Today's most widely deployed Web server APIs are based on a
-pool-of-processes server model.  The Web server consists of a parent
-process and a pool of child processes.  Processes do not share memory.
-An incoming request is assigned to an idle child at random.  The child
-runs the request to completion before accepting a new request.  A
-typical server has 32 child processes, a large server has 100 or 200.<p>
-
-In-memory caching works very poorly in this server model because
-processes do not share memory and incoming requests are assigned to
-processes at random.  For instance, to keep a frequently-used file
-available in memory the server must keep a file copy per child, which
-wastes memory.  When the file is modified all the children need to be
-notified, which is complex (the APIs don't provide a way to do it).<p>
-
-FastCGI is designed to allow effective in-memory caching.  Requests
-are routed from any child process to a FastCGI application server.
-The FastCGI application process maintains an in-memory cache.<p>
-
-In some cases a single FastCGI application server won't
-provide enough performance.  FastCGI provides two solutions:
-session affinity and multi-threading.<p>
-
-With session affinity you run a pool of application processes and the
-Web server routes requests to individual processes based on any
-information contained in the request.  For instance, the server can
-route according to the area of content that's been requested, or
-according to the user.  The user might be identified by an
-application-specific session identifier, by the user ID contained in
-an Open Market Secure Link ticket, by the Basic Authentication user
-name, or whatever.  Each process maintains its own cache, and session
-affinity ensures that each incoming request has access to the cache
-that will speed up processing the most.<p>
-
-With multi-threading you run an application process that is designed
-to handle several requests at the same time.  The threads handling
-concurrent requests share process memory, so they all have access to
-the same cache.  Multi-threaded programming is complex -- concurrency
-makes programs difficult to test and debug -- but with FastCGI you can
-write single threaded <i>or</i> multithreaded applications.<p>
-
-
-
-<h3><a name = "S4">4. Database Access</a></h3>
-
-
-Many Web server applications perform database access.  Existing
-databases contain a lot of valuable information; Web server
-applications allow companies to give wider access to the information.<p>
-
-Access to database management systems, even within a single machine,
-is via connection-oriented protocols.  An application "logs in" to a
-database, creating a connection, then performs one or more accesses.
-Frequently, the cost of creating the database connection is several
-times the cost of accessing data over an established connection.<p>
-
-To a first approximation database connections are just another type of
-state to be cached in memory by an application, so the discussion of
-caching above applies to caching database connections.<p>
-
-But database connections are special in one respect: They are often
-the basis for database licensing.  You pay the database vendor
-according to the number of concurrent connections the database system
-can sustain.  A 100-connection license costs much more than a
-5-connection license.  It follows that caching a database connection
-per Web server child process is not just wasteful of system's hardware
-resources, it could break your software budget.<p>
-
-
-
-<h3><a name = "S5">5. A Performance Test</a></h3>
-
-
-We designed a test application to illustrate performance issues.  The
-application represents a class of applications that deliver
-personalized content.  The test application is quite a bit simpler
-than any real application would be, but still illustrates the main
-performance issues.  We implemented the application using both FastCGI
-and a current Web server API, and measured the performance of each.<p>
-
-<h4><a name = "S5.1">5.1 Application Scenario</a></h4>
-
-The application is based on a user database and a set of
-content files.  When a user requests a content file, the application
-performs substitutions in the file using information from the
-user database.  The application then returns the modified
-content to the user.<p>
-
-Each request accomplishes the following:<p>
-
-<ol>
-    <li>authentication check: The user id is used to retrieve and
-        check the password.<p>
-
-    <li>attribute retrieval: The user id is used to retrieve all
-        of the user's attribute values.<p>
-
-    <li>file retrieval and filtering: The request identifies a
-        content file. This file is read and all occurrences of variable
-        names are replaced with the user's corresponding attribute values.
-        The modified HTML is returned to the user.<p>
-</ol>
-
-Of course, it is fair game to perform caching to shortcut
-any of these steps.<p>
-
-Each user's database record (including password and attribute
-values) is approximately 100 bytes long.  Each content file is 3,000
-bytes long.  Both database and content files are stored
-on disks attached to the server platform.<p>
-
-A typical user makes 10 file accesses with realistic think times
-(30-60 seconds) between accesses, then disappears for a long time.<p>
-
-
-<h4><a name = "S5.2">5.2 Application Design</a></h4>
-
-The FastCGI application maintains a cache of recently-accessed
-attribute values from the database.  When the cache misses
-the application reads from the database.  Because only a small
-number of FastCGI application processes are needed, each process
-opens a database connection on startup and keeps it open.<p>
-
-The FastCGI application is configured as multiple application
-processes.  This is desirable in order to get concurrent application
-processing during database reads and file reads.  Requests are routed
-to these application processes using FastCGI session affinity keyed on
-the user id.  This way all a user's requests after the first hit in
-the application's cache.<p>
-
-The API application does not maintain a cache; the API application has
-no way to share the cache among its processes, so the cache hit rate
-would be too low to make caching pay.  The API application opens and
-closes a database connection on every request; keeping database
-connections open between requests would result in an unrealistically
-large number of database connections open at the same time, and very
-low utilization of each connection.<p>
-
-
-<h4><a name = "S5.3">5.3 Test Conditions</a></h4>
-
-The test load is generated by 10 HTTP client processes.  The processes
-represent disjoint sets of users.  A process makes a request for a
-user, then a request for a different user, and so on until it is time
-for the first user to make another request.<p>
-
-For simplicity the 10 client processes run on the same machine
-as the Web server.  This avoids the possibility that a network
-bottleneck will obscure the test results.  The database system
-also runs on this machine, as specified in the application scenario.<p>
-
-Response time is not an issue under the test conditions.  We just
-measure throughput.<p>
-
-The API Web server is in these tests is Netscape 1.1.<p>
-
-
-<h4><a name = "S5.4">5.4 Test Results and Discussion</a></h4>
-
-Here are the test results:<p>
-
-<ul>
-<pre>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+   <HEAD>
+      <TITLE>
+         Understanding FastCGI Application Performance
+      </TITLE>
+<STYLE TYPE="text/css">
+ body {
+  background-color: #FFFFFF;
+  color: #000000;
+ }
+ :link { color: #cc0000 }
+ :visited { color: #555555 }
+ :active { color: #000011 }
+ div.c3 {margin-left: 2em}
+ h5.c2 {text-align: center}
+ div.c1 {text-align: center}
+</STYLE>
+   </HEAD>
+   <BODY>
+      <DIV CLASS="c1">
+         <A HREF="http://fastcgi.com"><IMG BORDER="0" SRC="../images/fcgi-hd.gif" ALT="[[FastCGI]]"></A>
+      </DIV>
+      <BR CLEAR="all">
+      <DIV CLASS="c1">
+         <H3>
+            Understanding FastCGI Application Performance
+         </H3>
+      </DIV>
+      <!--Copyright (c) 1996 Open Market, Inc.                                    -->
+      <!--See the file "LICENSE.TERMS" for information on usage and redistribution-->
+      <!--of this file, and for a DISCLAIMER OF ALL WARRANTIES.                   -->
+      <DIV CLASS="c1">
+         Mark R. Brown<BR>
+         Open Market, Inc.<BR>
+         <P>
+            10 June 1996<BR>
+         </P>
+      </DIV>
+      <P>
+      </P>
+      <H5 CLASS="c2">
+         Copyright &copy; 1996 Open Market, Inc. 245 First Street, Cambridge, MA 02142 U.S.A.<BR>
+         Tel: 617-621-9500 Fax: 617-621-1703 URL: <A HREF=
+         "http://www.openmarket.com/">http://www.openmarket.com/</A><BR>
+         $Id: fcgi-perf.htm,v 1.4 2002/02/25 00:42:59 robs Exp $<BR>
+      </H5>
+      <HR>
+      <UL TYPE="square">
+         <LI>
+            <A HREF="#S1">1. Introduction</A>
+         </LI>
+         <LI>
+            <A HREF="#S2">2. Performance Basics</A>
+         </LI>
+         <LI>
+            <A HREF="#S3">3. Caching</A>
+         </LI>
+         <LI>
+            <A HREF="#S4">4. Database Access</A>
+         </LI>
+         <LI>
+            <A HREF="#S5">5. A Performance Test</A> 
+            <UL TYPE="square">
+               <LI>
+                  <A HREF="#S5.1">5.1 Application Scenario</A>
+               </LI>
+               <LI>
+                  <A HREF="#S5.2">5.2 Application Design</A>
+               </LI>
+               <LI>
+                  <A HREF="#S5.3">5.3 Test Conditions</A>
+               </LI>
+               <LI>
+                  <A HREF="#S5.4">5.4 Test Results and Discussion</A>
+               </LI>
+            </UL>
+         </LI>
+         <LI>
+            <A HREF="#S6">6. Multi-threaded APIs</A>
+         </LI>
+         <LI>
+            <A HREF="#S7">7. Conclusion</A>
+         </LI>
+      </UL>
+      <P>
+      </P>
+      <HR>
+      <H3>
+         <A NAME="S1">1. Introduction</A>
+      </H3>
+      <P>
+         Just how fast is FastCGI? How does the performance of a FastCGI application compare with the performance of
+         the same application implemented using a Web server API?
+      </P>
+      <P>
+         Of course, the answer is that it depends upon the application. A more complete answer is that FastCGI often
+         wins by a significant margin, and seldom loses by very much.
+      </P>
+      <P>
+         Papers on computer system performance can be laden with complex graphs showing how this varies with that.
+         Seldom do the graphs shed much light on <I>why</I> one system is faster than another. Advertising copy is
+         often even less informative. An ad from one large Web server vendor says that its server &quot;executes web
+         applications up to five times faster than all other servers,&quot; but the ad gives little clue where the
+         number &quot;five&quot; came from.
+      </P>
+      <P>
+         This paper is meant to convey an understanding of the primary factors that influence the performance of Web
+         server applications and to show that architectural differences between FastCGI and server APIs often give an
+         &quot;unfair&quot; performance advantage to FastCGI applications. We run a test that shows a FastCGI
+         application running three times faster than the corresponding Web server API application. Under different
+         conditions this factor might be larger or smaller. We show you what you&#39;d need to measure to figure that
+         out for the situation you face, rather than just saying &quot;we&#39;re three times faster&quot; and moving
+         on.
+      </P>
+      <P>
+         This paper makes no attempt to prove that FastCGI is better than Web server APIs for every application. Web
+         server APIs enable lightweight protocol extensions, such as Open Market&#39;s SecureLink extension, to be
+         added to Web servers, as well as allowing other forms of server customization. But APIs are not well matched
+         to mainstream applications such as personalized content or access to corporate databases, because of API
+         drawbacks including high complexity, low security, and limited scalability. FastCGI shines when used for the
+         vast majority of Web applications.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S2">2. Performance Basics</A>
+      </H3>
+      <P>
+         Since this paper is about performance we need to be clear on what &quot;performance&quot; is.
+      </P>
+      <P>
+         The standard way to measure performance in a request-response system like the Web is to measure peak request
+         throughput subject to a response time constriaint. For instance, a Web server application might be capable of
+         performing 20 requests per second while responding to 90% of the requests in less than 2 seconds.
+      </P>
+      <P>
+         Response time is a thorny thing to measure on the Web because client communications links to the Internet have
+         widely varying bandwidth. If the client is slow to read the server&#39;s response, response time at both the
+         client and the server will go up, and there&#39;s nothing the server can do about it. For the purposes of
+         making repeatable measurements the client should have a high-bandwidth communications link to the server.
+      </P>
+      <P>
+         [Footnote: When designing a Web server application that will be accessed over slow (e.g. 14.4 or even 28.8
+         kilobit/second modem) channels, pay attention to the simultaneous connections bottleneck. Some servers are
+         limited by design to only 100 or 200 simultaneous connections. If your application sends 50 kilobytes of data
+         to a typical client that can read 2 kilobytes per second, then a request takes 25 seconds to complete. If your
+         server is limited to 100 simultaneous connections, throughput is limited to just 4 requests per second.]
+      </P>
+      <P>
+         Response time is seldom an issue when load is light, but response times rise quickly as the system approaches
+         a bottleneck on some limited resource. The three resources that typical systems run out of are network I/O,
+         disk I/O, and processor time. If short response time is a goal, it is a good idea to stay at or below 50% load
+         on each of these resources. For instance, if your disk subsystem is capable of delivering 200 I/Os per second,
+         then try to run your application at 100 I/Os per second to avoid having the disk subsystem contribute to slow
+         response times. Through careful management it is possible to succeed in running closer to the edge, but
+         careful management is both difficult and expensive so few systems get it.
+      </P>
+      <P>
+         If a Web server application is local to the Web server machine, then its internal design has no impact on
+         network I/O. Application design can have a big impact on usage of disk I/O and processor time.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S3">3. Caching</A>
+      </H3>
+      <P>
+         It is a rare Web server application that doesn&#39;t run fast when all the information it needs is available
+         in its memory. And if the application doesn&#39;t run fast under those conditions, the possible solutions are
+         evident: Tune the processor-hungry parts of the application, install a faster processor, or change the
+         application&#39;s functional specification so it doesn&#39;t need to do so much work.
+      </P>
+      <P>
+         The way to make information available in memory is by caching. A cache is an in-memory data structure that
+         contains information that&#39;s been read from its permanent home on disk. When the application needs
+         information, it consults the cache, and uses the information if it is there. Otherwise is reads the
+         information from disk and places a copy in the cache. If the cache is full, the application discards some old
+         information before adding the new. When the application needs to change cached information, it changes both
+         the cache entry and the information on disk. That way, if the application crashes, no information is lost; the
+         application just runs more slowly for awhile after restarting, because the cache doesn&#39;t improve
+         performance when it is empty.
+      </P>
+      <P>
+         Caching can reduce both disk I/O and processor time, because reading information from disk uses more processor
+         time than reading it from the cache. Because caching addresses both of the potential bottlenecks, it is the
+         focal point of high-performance Web server application design. CGI applications couldn&#39;t perform in-memory
+         caching, because they exited after processing just one request. Web server APIs promised to solve this
+         problem. But how effective is the solution?
+      </P>
+      <P>
+         Today&#39;s most widely deployed Web server APIs are based on a pool-of-processes server model. The Web server
+         consists of a parent process and a pool of child processes. Processes do not share memory. An incoming request
+         is assigned to an idle child at random. The child runs the request to completion before accepting a new
+         request. A typical server has 32 child processes, a large server has 100 or 200.
+      </P>
+      <P>
+         In-memory caching works very poorly in this server model because processes do not share memory and incoming
+         requests are assigned to processes at random. For instance, to keep a frequently-used file available in memory
+         the server must keep a file copy per child, which wastes memory. When the file is modified all the children
+         need to be notified, which is complex (the APIs don&#39;t provide a way to do it).
+      </P>
+      <P>
+         FastCGI is designed to allow effective in-memory caching. Requests are routed from any child process to a
+         FastCGI application server. The FastCGI application process maintains an in-memory cache.
+      </P>
+      <P>
+         In some cases a single FastCGI application server won&#39;t provide enough performance. FastCGI provides two
+         solutions: session affinity and multi-threading.
+      </P>
+      <P>
+         With session affinity you run a pool of application processes and the Web server routes requests to individual
+         processes based on any information contained in the request. For instance, the server can route according to
+         the area of content that&#39;s been requested, or according to the user. The user might be identified by an
+         application-specific session identifier, by the user ID contained in an Open Market Secure Link ticket, by the
+         Basic Authentication user name, or whatever. Each process maintains its own cache, and session affinity
+         ensures that each incoming request has access to the cache that will speed up processing the most.
+      </P>
+      <P>
+         With multi-threading you run an application process that is designed to handle several requests at the same
+         time. The threads handling concurrent requests share process memory, so they all have access to the same
+         cache. Multi-threaded programming is complex -- concurrency makes programs difficult to test and debug -- but
+         with FastCGI you can write single threaded <I>or</I> multithreaded applications.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S4">4. Database Access</A>
+      </H3>
+      <P>
+         Many Web server applications perform database access. Existing databases contain a lot of valuable
+         information; Web server applications allow companies to give wider access to the information.
+      </P>
+      <P>
+         Access to database management systems, even within a single machine, is via connection-oriented protocols. An
+         application &quot;logs in&quot; to a database, creating a connection, then performs one or more accesses.
+         Frequently, the cost of creating the database connection is several times the cost of accessing data over an
+         established connection.
+      </P>
+      <P>
+         To a first approximation database connections are just another type of state to be cached in memory by an
+         application, so the discussion of caching above applies to caching database connections.
+      </P>
+      <P>
+         But database connections are special in one respect: They are often the basis for database licensing. You pay
+         the database vendor according to the number of concurrent connections the database system can sustain. A
+         100-connection license costs much more than a 5-connection license. It follows that caching a database
+         connection per Web server child process is not just wasteful of system&#39;s hardware resources, it could
+         break your software budget.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S5">5. A Performance Test</A>
+      </H3>
+      <P>
+         We designed a test application to illustrate performance issues. The application represents a class of
+         applications that deliver personalized content. The test application is quite a bit simpler than any real
+         application would be, but still illustrates the main performance issues. We implemented the application using
+         both FastCGI and a current Web server API, and measured the performance of each.
+      </P>
+      <P>
+      </P>
+      <H4>
+         <A NAME="S5.1">5.1 Application Scenario</A>
+      </H4>
+      <P>
+         The application is based on a user database and a set of content files. When a user requests a content file,
+         the application performs substitutions in the file using information from the user database. The application
+         then returns the modified content to the user.
+      </P>
+      <P>
+         Each request accomplishes the following:
+      </P>
+      <P>
+      </P>
+      <OL>
+         <LI>
+            authentication check: The user id is used to retrieve and check the password.
+            <P>
+            </P>
+         </LI>
+         <LI>
+            attribute retrieval: The user id is used to retrieve all of the user&#39;s attribute values.
+            <P>
+            </P>
+         </LI>
+         <LI>
+            file retrieval and filtering: The request identifies a content file. This file is read and all occurrences
+            of variable names are replaced with the user&#39;s corresponding attribute values. The modified HTML is
+            returned to the user.<BR>
+            <BR>
+         </LI>
+      </OL>
+      <P>
+         Of course, it is fair game to perform caching to shortcut any of these steps.
+      </P>
+      <P>
+         Each user&#39;s database record (including password and attribute values) is approximately 100 bytes long.
+         Each content file is 3,000 bytes long. Both database and content files are stored on disks attached to the
+         server platform.
+      </P>
+      <P>
+         A typical user makes 10 file accesses with realistic think times (30-60 seconds) between accesses, then
+         disappears for a long time.
+      </P>
+      <P>
+      </P>
+      <H4>
+         <A NAME="S5.2">5.2 Application Design</A>
+      </H4>
+      <P>
+         The FastCGI application maintains a cache of recently-accessed attribute values from the database. When the
+         cache misses the application reads from the database. Because only a small number of FastCGI application
+         processes are needed, each process opens a database connection on startup and keeps it open.
+      </P>
+      <P>
+         The FastCGI application is configured as multiple application processes. This is desirable in order to get
+         concurrent application processing during database reads and file reads. Requests are routed to these
+         application processes using FastCGI session affinity keyed on the user id. This way all a user&#39;s requests
+         after the first hit in the application&#39;s cache.
+      </P>
+      <P>
+         The API application does not maintain a cache; the API application has no way to share the cache among its
+         processes, so the cache hit rate would be too low to make caching pay. The API application opens and closes a
+         database connection on every request; keeping database connections open between requests would result in an
+         unrealistically large number of database connections open at the same time, and very low utilization of each
+         connection.
+      </P>
+      <P>
+      </P>
+      <H4>
+         <A NAME="S5.3">5.3 Test Conditions</A>
+      </H4>
+      <P>
+         The test load is generated by 10 HTTP client processes. The processes represent disjoint sets of users. A
+         process makes a request for a user, then a request for a different user, and so on until it is time for the
+         first user to make another request.
+      </P>
+      <P>
+         For simplicity the 10 client processes run on the same machine as the Web server. This avoids the possibility
+         that a network bottleneck will obscure the test results. The database system also runs on this machine, as
+         specified in the application scenario.
+      </P>
+      <P>
+         Response time is not an issue under the test conditions. We just measure throughput.
+      </P>
+      <P>
+         The API Web server is in these tests is Netscape 1.1.
+      </P>
+      <P>
+      </P>
+      <H4>
+         <A NAME="S5.4">5.4 Test Results and Discussion</A>
+      </H4>
+      <P>
+         Here are the test results:
+      </P>
+      <P>
+      </P>
+      <DIV CLASS="c3">
+<PRE>
     FastCGI  12.0 msec per request = 83 requests per second
     API      36.6 msec per request = 27 requests per second
-</pre>
-</ul>
-
-Given the big architectural advantage that the FastCGI application
-enjoys over the API application, it is not surprising that the
-FastCGI application runs a lot faster.  To gain a deeper
-understanding of these results we measured two more conditions:<p>
-
-<ul>
-    <li>API with sustained database connections.  If you could
-        afford the extra licensing cost, how much faster would
-        your API application run?<p>
-
-<pre>
+</PRE>
+      </DIV>
+      <P>
+         Given the big architectural advantage that the FastCGI application enjoys over the API application, it is not
+         surprising that the FastCGI application runs a lot faster. To gain a deeper understanding of these results we
+         measured two more conditions:
+      </P>
+      <P>
+      </P>
+      <UL>
+         <LI>
+            API with sustained database connections. If you could afford the extra licensing cost, how much faster
+            would your API application run?
+            <P>
+            </P>
+<PRE>
     API      16.0 msec per request = 61 requests per second
-</pre>
-
-        Answer: Still not as fast as the FastCGI application.<p>
-
-    <li>FastCGI with cache disabled.  How much benefit does the
-        FastCGI application get from its cache?<p>
-
-<pre>
+</PRE>
+            Answer: Still not as fast as the FastCGI application.
+            <P>
+            </P>
+         </LI>
+         <LI>
+            FastCGI with cache disabled. How much benefit does the FastCGI application get from its cache?
+            <P>
+            </P>
+<PRE>
     FastCGI  20.1 msec per request = 50 requests per second
-</pre>
-
-        Answer: A very substantial benefit, even though the database
-        access is quite simple.<p>
-</ul>
-
-What these two extra experiments show is that if the API and FastCGI
-applications are implemented in exactly the same way -- caching
-database connections but not caching user profile data -- the API
-application is slightly faster.  This is what you'd expect, since the
-FastCGI application has to pay the cost of inter-process
-communication not present in the API application.<p>
-
-In the real world the two applications would not be implemented in the
-same way.  FastCGI's architectural advantage results in much higher
-performance -- a factor of 3 in this test.  With a remote database
-or more expensive database access the factor would be higher.
-With more substantial processing of the content files the factor
-would be smaller.<p>
-
-
-
-<h3><a name = "S6">6. Multi-threaded APIs</a></h3>
-
-
-Web servers with a multi-threaded internal structure (and APIs to
-match) are now starting to become more common.  These servers don't
-have all of the disadvantages described in Section 3.  Does this mean
-that FastCGI's performance advantages will disappear?<p>
-
-A superficial analysis says yes.  An API-based application in a
-single-process, multi-threaded server can maintain caches and database
-connections the same way a FastCGI application can.  The API-based
-application does not pay for inter-process communication, so the
-API-based application will be slightly faster than the FastCGI
-application.<p>
-
-A deeper analysis says no.  Multi-threaded programming is complex,
-because concurrency makes programs much more difficult to test and
-debug.  In the case of multi-threaded programming to Web server APIs,
-the normal problems with multi-threading are compounded by the lack of
-isolation between different applications and between the applications
-and the Web server.  With FastCGI you can write programs in the
-familiar single-threaded style, get all the reliability and
-maintainability of process isolation, and still get very high
-performance.  If you truly need multi-threading, you can write
-multi-threaded FastCGI and still isolate your multi-threaded
-application from other applications and from the server.  In short,
-multi-threading makes Web server APIs unusable for practially all
-applications, reducing the choice to FastCGI versus CGI.  The
-performance winner in that contest is obviously FastCGI.<p>
-
-
-
-<h3><a name = "S7">7. Conclusion</a></h3>
-
-
-Just how fast is FastCGI?  The answer: very fast indeed.  Not because
-it has some specially-greased path through the operating system, but
-because its design is well matched to the needs of most applications.
-We invite you to make FastCGI the fast, open foundation for your Web
-server applications.<p>
-
-
-
-<hr>
-<a href="http://www.openmarket.com/"><IMG SRC="omi-logo.gif" ALT="OMI Home Page"></a>
-
-<address>
-&#169 1995, Open Market, Inc. / mbrown@openmarket.com
-</address>
+</PRE>
+            Answer: A very substantial benefit, even though the database access is quite simple.<BR>
+            <BR>
+         </LI>
+      </UL>
+      <P>
+         What these two extra experiments show is that if the API and FastCGI applications are implemented in exactly
+         the same way -- caching database connections but not caching user profile data -- the API application is
+         slightly faster. This is what you&#39;d expect, since the FastCGI application has to pay the cost of
+         inter-process communication not present in the API application.
+      </P>
+      <P>
+         In the real world the two applications would not be implemented in the same way. FastCGI&#39;s architectural
+         advantage results in much higher performance -- a factor of 3 in this test. With a remote database or more
+         expensive database access the factor would be higher. With more substantial processing of the content files
+         the factor would be smaller.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S6">6. Multi-threaded APIs</A>
+      </H3>
+      <P>
+         Web servers with a multi-threaded internal structure (and APIs to match) are now starting to become more
+         common. These servers don&#39;t have all of the disadvantages described in Section 3. Does this mean that
+         FastCGI&#39;s performance advantages will disappear?
+      </P>
+      <P>
+         A superficial analysis says yes. An API-based application in a single-process, multi-threaded server can
+         maintain caches and database connections the same way a FastCGI application can. The API-based application
+         does not pay for inter-process communication, so the API-based application will be slightly faster than the
+         FastCGI application.
+      </P>
+      <P>
+         A deeper analysis says no. Multi-threaded programming is complex, because concurrency makes programs much more
+         difficult to test and debug. In the case of multi-threaded programming to Web server APIs, the normal problems
+         with multi-threading are compounded by the lack of isolation between different applications and between the
+         applications and the Web server. With FastCGI you can write programs in the familiar single-threaded style,
+         get all the reliability and maintainability of process isolation, and still get very high performance. If you
+         truly need multi-threading, you can write multi-threaded FastCGI and still isolate your multi-threaded
+         application from other applications and from the server. In short, multi-threading makes Web server APIs
+         unusable for practially all applications, reducing the choice to FastCGI versus CGI. The performance winner in
+         that contest is obviously FastCGI.
+      </P>
+      <P>
+      </P>
+      <H3>
+         <A NAME="S7">7. Conclusion</A>
+      </H3>
+      <P>
+         Just how fast is FastCGI? The answer: very fast indeed. Not because it has some specially-greased path through
+         the operating system, but because its design is well matched to the needs of most applications. We invite you
+         to make FastCGI the fast, open foundation for your Web server applications.
+      </P>
+      <P>
+      </P>
+      <HR>
+      <A HREF="http://www.openmarket.com/"><IMG SRC="omi-logo.gif" ALT="OMI Home Page"></A> 
+      <ADDRESS>
+         &copy; 1995, Open Market, Inc. / mbrown@openmarket.com
+      </ADDRESS>
+   </BODY>
+</HTML>
 
-</body>
-</html>
-</body>
-</html>