Keeping the 400lb. Gorilla at Bay:

Optimizing Web Performance

James Rubarth-Lay

9 May 1996

Table of Contents


Abstract

The HyperText Transfer Protocol (HTTP) is the 400 pound gorilla of Internet protocols. This paper describes HTTP and Web server technology and surveys two broad strategies for keeping the use of HTTP from bringing the rest of the Internet to its knees. First, strategies for improving Web server performance are explored. Second, the HTTP protocol[1] itself can be optimized.

Introduction

What is HTTP?

HTTP or the HyperText Transfer Protocol is a standard method for transmitting information through the Internet. The interconnections between hypermedia documents delivered by HTTP form a web, known as the World-Wide Web global initiative. HTTP and its sibling standard, the document markup language known as HyperText Markup Language or HTML, have done more than anything to make information exchange accessible to the masses and together have been the principal contributing factor in the explosive growth of the Internet. HTTP is the fastest growing protocol on the Internet today and the primary protocol for information exchange according to Internet World. [Musciano 1/96]

The protocol was designed to be a fast, lightweight means to deliver distributed hypermedia information systems. HTTP places little load on the CPU or memory resources of a server, certainly compared with other protocols. It operates in a request and respond fashion. The client system requests an object from the server and the server responds by sending the object to the client.

What's Wrong with HTTP?

Gigabytes of hypermedia are transmitted through the Internet every day using HTTP. If the protocol is so successful, why does it need to be improved? The attainment of the protocol belies the need to improve it. In part, because HTTP is so successful, it must be modified in order to continue its phenomenal growth. [Spero NG] Without improvements in both server capacity and protocol efficiency, the World-Wide Web cannot continue its current rate of growth.

As an indication of the demands placed on a server and a network by HTTP, consider the following: Sun, the leading manufacturer of Web servers[2], estimates a single client system combined with the responses from the Web server will saturate a 10 Mbps 10Base-T Ethernet network, assuming a 60% bandwidth utilization due to collision activity. [Sun]

Evaluation and Performance

Performance of a Web server is dependent upon a number of variables: the server hardware and operating environment; the server application; the network protocol; and the network, hardware, bandwidth, and congestion. Perception of that performance depends also on the client side; the client platform and operating environment; and the Web client. Some Web clients take steps to improve the perception of performance, for example, by displaying inline images while they are being downloaded instead of waiting until the entire image is downloaded.

There are four metrics most often used to measure the capacity of Web servers. These are:

  1. Connections served or requests made per second;
  2. Throughput in bytes per second, which is dependent upon the bandwidth of the data pipe;
  3. Round-trip time (RTT), a measure of how long it takes for a packet to be sent from the client plus the time a response from the server takes to be received by the client, completing the request; and
  4. Errors.
The two key elements of HTTP performance are latency and throughput:

  1. Latency is measured by the RTT and is independent of the object size.
  2. Throughput is a measure of how long it takes to send data, up to the carrying capacity of the data pipe. Improving throughput is simply a matter of employing faster, higher bandwidth networks.

Requests per second (rps or HTTPops/sec)

The connection rate is a measure of how many HTTP requests a server can manage within a given length of time. The server must open, service, and close a connection for each HTTP request. The unit of measure is variously regarded as requests per second (rps) or HTTPops/sec. In measuring the connection rate for a server, its capacity must be tested under various workload conditions. The sustained load may be exceeded at times by peak loads that can be five to ten times greater than the average daily load. The capacity of the server must be tested on small, medium, and large files, on both static and dynamic HTML files, CGI and API-based content, and database accesses.

This is an important metric for the perception of the reliability of a server and the site it serves. A Web server that has a connection rate lower than the rate at which requests arrive will result in users receiving timeout or "connection refused" messages.

Throughput (bps) AKA bandwidth

Throughput is the measure of the maximum amount of data the server can send through all open connections during a given amount of time the total number of bytes transferred per unit time. The user's experience of a site whose server's bandwidth is less than the demand will be diminished as the per-client throughput lessens to a trickle. Many a server has been reduced by a demanding workload to the performance of a Teletype machine (50 cps) as far as individual clients go.

When the throughput a server can handle approaches the bandwidth of the network, then the network is saturated and will have to be upgraded for any additional performance to be achieved. The perceived throughput of a server can be limited by the network between the server and the client, including such factors as the bandwidth of network connections, WAN/LAN gateways, routers, and network congestion. Bandwidth is limited by the bottleneck of the carrying capacity of the least capacious link or node of the data pipe.

Round-Trip Time (RTT)

Response time is a measure of how long it takes the server to service a client request. A round-trip time of more than a second or two will feel sluggish to the user. Here, too, network conditions can reduce the perceived performance of a Web server. Significant delays occur because the HTTP protocol requires many small-packet round trips, particularly when the network path is congested.

Error rate

Errors per second is the measure of how many HTTP requests were lost or not handled by a server. The perception of reliability depends on a low error rate.

How is Performance Measured?

Evaluation of server performance can use operational data or artificial testing. Analyses of operational data include looking at server logs and monitoring of network, server operating system, and server software. In the most basic terms, performance of a Web server can be measured by timing how long a server takes to respond to a request and to count the number of bytes delivered per unit time. While analyses of operational data use real-world conditions and can accurately measure what the user experiences, the results are dependent upon too many variables to make comparisons between different configurations reliable.

Benchmarking

Benchmarks are one kind of synthetic test of performance. A benchmark procedure uses a predefined set of data and measures the results returned by the system under examination. Benchmarks are intended to make comparisons easy. A caveat to benchmark designers, however, is that the datasets used may not accurately reflect what an actual user may experience. A crucial design consideration for the benchmark program and the datasets employed is how to predict real-world performance. Benchmarks must be validated to prove the results are indicative of the performance experienced by the user. In order to evaluate this, the benchmark designers must show that the dataset accurately models the workload encountered in the wild.

A Web benchmark tries to simulate the activity of a Web server by emulating the access patterns of a prototypical client set. It takes a set of client programs that send Web requests to the server. The server responses are then measured, usually in terms of response time and throughput. Three important considerations in Web benchmark design are the mix of HTTP methods (for example, GET, POST, PUT) used in the access suite, the size and number of files to be retrieved, and the arrival rate of the requests. Different operations put different demands on the server. The size of files to be retrieved is significant in that larger files take longer to transfer. The number of files to be retrieved affects whether the server might be able to cache the files, seriously affecting the response time.

In addition to the characteristics of the files requested of a server, the workload of a server depends upon the timing of the requests. A typical client transaction sequence requests an HTML page then a series of requests for the icons and inline images referenced by the page. This bursty traffic, the multiple simultaneous requests, puts a greater demand on a server than if the requests are staggered or evenly distributed in time. A benchmark that attempts to model real-world performance of a server will need to duplicate the balance of file sizes, the number of files, and the clustering of requests.

Additional factors in consideration of a server are: the number of client systems, the distribution of requests over time, simulation of slow network conditions (congestion, low bandwidth), imagemaps, CGI programs, database transactions, security (encryption and authentication), and commerce (on-line payment mechanisms). The latter two procedures are notable in that they reverse the usual pattern in that the server initiates the request for information, asking for authentication (user/password) and mutually acceptable charge information, respectively.

SGI WebStone 1.1 benchmark

WebStone, a Web benchmarking package from Silicon Graphics, Inc. (SGI), was the first complete Web server benchmark and at this writing is the only completed Web server benchmark. It has a Web browser interface, a standard set of metrics, and standard reports for evaluating the performance of any Web server regardless of its hardware architecture or operating system.

WebStone manages a number of clients running on one or more UNIX workstations. These clients generate workloads for the server being tested, based on random HTTP/1.0 GET requests. The workload is configurable to several scenarios. In addition to static HTML pages, WebStone can sample CGI and API code and dynamic pages generated by an external data source such as an RDBMS or a document management system. [Blakeley]

SPEC Webperf benchmark (in development)

With WebStone available now, why might Web server designers and managers need another benchmark? Because the code for WebStone was developed by a Web server manufacturer, for all that the source code is publicly available, a certain bias may be expected. Without an impartial body controlling the code, benchmark results mean little because results from similar configuration vary wildly. Investigating the claims made by the different Web server vendors could be a separate paper of its own.

The Standard Performance Evaluation Corporation (SPEC) is in the development phase of a World Wide Web server benchmark. While it was the de facto standard at the beginning of the year, WebStone may be replaced by the Webperf benchmark, which draws extensively on WebStone in terms of its style. Webperf is due to be released this year. Webperf has a Web browser interface. It generates a workload with one or more client processes on one or more hosts. The clients measure the response time and throughput. The results are compiled and reported in a standard format.

It is expected that when the benchmark application is finished that it will become the standard by which Web servers are measured. The SPEC Web benchmark is described by Rosenthal as a superset of the WebStone benchmark, at present the only benchmark for Web servers. [Sterlicchi]

The reports generated by Webperf contain a number of metrics. The fundamental figure reported by Webperf, intended to function as a comparison between systems, is the "SPECWebOps/second," the number of requests successfully served divided by the length of the test run.

Back to Table of Contents

Web Server Optimization

Web server performance is important. In the March issue of SunWorld Online, estimates of Web server performance running on a SPARCstation 20 Model 71 ranged from 20 to 300 operations per second. [Cockcroft].

Current servers may be divided into three categories of capacity:

  1. Web server forks a new process for each request. Capacity maximum 20 rps on uniprocessor 75-MHz SPARCstation 20.
  2. Web server uses multithreading or pre-allocated process pool. Referenced SPARCstation capacity 100 rps.
  3. Web server uses keep-alive option in HTTP version 1.1. May be able to satisfy 250 - 300 rps.
Anticipated future Web server technology will accommodate multiplexed requests over a single TCP/IP connection. This model resembles a distributed file system like NFS running over TCP/IP. Projected performance could be in the range of 500 to 900 rps. Such an architecture will move the performance bottleneck from the server to the network and file I/O.

Use standalone server daemon - not inetd

There are two standard methods by which a UNIX daemon is initiated. A standalone server starts once when it is invoked. It is terminated when killed by the operator or when the system shuts down. The second method is to use an Internet daemon, inetd, that listens on a number of ports for requests for services. When it gets a request on port 80, inetd starts httpd, which services the request then terminates. An inetd-based server will spend a significant time starting and initializing (fork and exec) httpd for each request. It has been shown to service less than half the throughput of a standalone httpd. [McGrath 2/96] All currently supported releases of the most widely used UNIX-based Web server daemons have the ability to be run in standalone mode.

Use threads or process pools - not fork/exec

The "process-per-connection" architecture, which forks a new process for each connection, while it hews to the stateless model of the HTTP scheme, is less than efficient. The time and resources required by the fork and exec operations are significant, particularly in light of the fact that the typical Web request is very short. The use of threads or pre-allocated pools of processes to service TCP connections greatly reduces the overhead involved in forking a separate process. [Pradmanaghan] Multi-threading or pre-allocating processes can improve performance by up to 500 percent.

Server pools eliminate the overhead of forking a new process when a request is received. The pool of processes model has the server allocating a pool of helper processes at server startup time. When the dispatcher receives a request it distributes it to the next idle helper process in the pool. If no more processes are free, a new process or cluster of processes is created.

If more requests are received once the pool is maxed-out, the requests are not serviced and the client gets a busy signal. Once the peak load goes down, idle processes can be killed down to the minimum pool size. NCSA 1.4 pre-allocates processes.

A more dynamic pool of processes model is load-based, counting the number of idle server processes. When the number of idle processes falls below the minimum number of spares, extra servers are created. When the number of idle server processes grows beyond the maximum number of spares, the extras are terminated. [Musciano 2/96]

Threads are not only faster to establish than processes, but have a lower system resource overhead. [Sun] The use of multiple connections per process or "multithreading" is a good design and can take advantage of multiple processors. Threads take very little resources above that already used by the daemon and are much faster to start than processes. The main drawback to the use of multithreading is that it is not readily portable. Netscape 2.0, Phttpd and Open Market use multithreading.

Use APIs in lieu of CGIs or compile scripts

The use of CGI to extend a server's functionality is less efficient than extending the HTTP to include more methods and executing the instructions as a thread within the server instead of running the CGI program in a separate process. [Edwards] Using an API instead of a CGI has the advantage of integrating the extensions to the server within the server's process. This eliminates the need to go to the OS for communications between the server and the script.

Clusters of servers and a DNS distributor: A Scaleable Web Server

When a Web site experiences exponential growth, as many popular sites and the World Wide Web as a whole have, it will rapidly exceed the capacity of any single-server architecture. The solution determined by NCSA was to use load distribution across a multi-server configuration. To implement the distribution of HTTP requests to the stations in the cluster, the designers made use of DNS load balancing by employing a random rotation or round-robin DNS for distributing HTTP requests across the server cluster. The Domain Name Resolver is in effect a switch through which requests travel from the client to the Web server that will handle the request. By returning the IP address of servers in turn or to the next idle server, the workload is distributed more or less evenly across the entire cluster.

While they could have divided the file space between servers, this was deemed an unsatisfactory solution because the manipulation of file trees and rewriting hypermedia links would be both labor-intensive and not transparent to the user base. The alternative, a more attractive solution, was to configure a cluster of identical Web servers, each sharing the same file structure and answering to a common host name. The problem of maintaining a synchronized, coherent set of files across the cluster was solved by the use of a distributed file system. The use of large caches local to each server reduced the latency inherent in locating and retrieving the requested file from within the DFS. [Katz]

The Web server designers at Netscape Corp. took a similar approach. Their cluster did not use identically configured machines, as NCSA did. Their DNS distributor used a more sophisticated algorithm. Instead of using a round-robin rotation, which seemed to have a bias, the Netscape distributor polled the servers and passed on the connection to the next available server. This allowed the server cluster to balance the load between the component servers based on the capacity of the individual servers. [Mosedale]

A Hierarchical Internet Object Cache: Proxy servers

A hierarchical cache architecture works by having a proxy server cache data objects as it serves them. It attempts to resolve misses passed to it from a lower level cache, as well as from neighbor caches at the same level. When the cache receives a request for a URL, it determines whether it has the requested object and if it does it returns the object. If the object is not in the cache, the cache does two things. First, it performs a remote procedure call to all its neighbors and parents in the hierarchy to see whether they have cached the object. Second, it puts a request to the object's home site. The cache takes the fastest response to fetch the object. Certain configurable substrings in the URL tell the cache not to cache the URL but to retrieve the object directly from the object's home. [Chankhunthod] Proxy servers operating at key routing points on the Internet could greatly reduce both latency and traffic. For example, a proxy server running at a router linking North America with Europe could monitor URLs requesting objects from England. Cached objects would not have to be transmitted through the scarce resource of intercontinental communications. Further, the proxy server would have a lower RTT than an overseas server.

A drawback to hierarchical caches is the latency introduced by the cache's operation. The hierarchy must not be constructed with too many levels or the cache latency will defeat the savings. Dynamic HTML pages, such as those generated by CGI scripts, cannot be cached and the proxy servers will have to recognize non-cacheable objects.

Other Web Server Performance Considerations

Factors affecting the performance of a Web server include the hardware platform and its component subsystems: CPU, RAM, disk I/O and file cache, network I/O. Items the Web server administrator can take to optimize performance on an existing installation:

Back to Table of Contents

The HTTP Protocol

How the Protocol Works

The HyperText Transfer Protocol [Berners-Lee 94] uses the Transfer Control Protocol (TCP) [Postel] as a transport layer to retrieve distributed hypermedia. The HTTP protocol is a very simple one: the client establishes a connection to the server then issues a request. The server processes the request, returns a response, then closes the connection. See Figure 1. below.

Client opens connection and requests object

The object request format is simple. HTTP requests consist of a method, a URL, a set of headers, and an optional data field. The first line specifies a method (for example, GET, PUT, POST, etc.), the object to which the method is to be applied, and a string specifying the HTTP level the client can accept, for example "HTTP/1.0". Optional subsequent lines may send headers in the MIME, RFC-822 [Crocker], format, specifying the possible object types and methods the client or server supports. The cost of specifying all possible types is a request packet that can exceed 1K. Consequently, few servers support type negotiation. The Data field is used with certain methods such as PUT. The length of the Data field is specified by one of the following:

  1. The content-length field,
  2. The content-type field may specify a boundary delimiter a la MIME syntax,
  3. The server may close the TCP connection after the last data byte.

Server services request and closes connection

The response is likewise simple. The first line indicates the HTTP level of the server, a result code, and an optional message. The first line is followed by a series of optional headers that describe the object. After an empty line (<CR/LF><CR/LF>), the server sends the requested object. After sending the data, the server drops the connection.

Illustration of HTTP request

Figure 1

Notes about the above figure (Figure 1):

Sources of HTTP Latency

The current HTTP protocol uses a separate TCP connection for each file request. The overhead for the network round trips required for a Web page and every individual graphic on it is significant. The mandatory round trips are:

  1. The client opens the TCP connection, resulting in an exchange of SYN packets as part of TCP's three-way handshake procedure. The client sends a connection request (SYN), the server responds (SYN), and the client acknowledges the response (ACK).
  2. The client transmits an HTTP request to the server; the server may have to read from its disk to fulfill the request, and then transmits the response to the client. In the example shown, it is assumed that the response is small enough to fit into a single data packet, although in practice it might not. The server then closes the TCP connection, although if it has sent a Content-length field, the client need not wait for the connection termination before continuing.
  3. After parsing the returned HTML document to extract the URLs for inlined images, the client opens a new TCP connection to the server, resulting in another exchange of SYN packets.
  4. The client again transmits an HTTP request, this time for the first inlined image. The server obtains the image file, and starts transmitting it to the client.
Thus there is a minimum transaction time of two RTTs and an average of two RTTs per object retrieved. Each additional inlined image after the first one requires at least two further round-trips.

The TCP overhead introduces latencies:

Slow Start

The TCP protocol uses windows, in which the sender may send out new packets even while it has not received acknowledgments for previous packets. The number of such unacknowledged packets is the window size. The best transmission rate occurs when the rate of acknowledgments equals the rate at which packets are going out. In congested network conditions, sending a large window worth of packets worsens the congestion.

At the outset of a connection, the sender cannot know how congested the network is. The "slow-start" approach requires the TCP sender to open its "congestion window" gradually, starting with a window value of one (one unacknowledged packet at a time). As more packets are acknowledged, the window size is increased. When a segment is lost and times out, the window is narrowed. Full throughput is not reached until the effective window size is at least the product of the round-trip delay and the available network bandwidth.

Slow start is most effective with connections that last a relatively long time. Because HTTP connections tend to be rather short and to consist of few packets, slow start reduces the throughput, requiring the addition of at least one RTT to the total transaction time. [Spero Analysis] An additional drawback to slow start is the fact that the congestion information is not shared between connections to the same host. This means that for each connection between a pair of hosts the same slow start process takes place. A related drawback is that multiple simultaneous connections between hosts can interfere with each other when the network becomes congested. [Spero NG]

A related performance issue is the TCP retransmit timeout. TCP starts with a short estimate of the RTT and tends to retransmit the first few packets of a connection. An improvement to the TCP architecture will make a better initial estimate and a better convergence on an optimal timeout value.

Solutions:

Keep TCP connections open and reuse them: Keep-Alive

The cost of opening a new connection for each transaction can be eliminated by reusing existing TCP connections. This way the transaction time will be the time to send a request plus the RTT plus the processing time on the server plus the time to send the response. When the Web server keeps TCP connections open and does not close them at end of an HTTP exchange, the maximum number of available TCP connections will be reached. The Web server then closes the oldest idle connections first. The HTTP version 1.1 draft specifies the optional use of Keep-Alive connections. [Fielding] Requesting a Keep-Alive connection when GETing a file means the browser can reuse the connection to get subsequent files from the server. Two Web servers have incorporated the Keep-Alive support. These are NCSA httpd and Spyglass Mosaic. [Spyglass]

Cluster requests into one HTTP exchange

At present, each request requires a separate RTT delay. If, instead of returning a single file an HTTP request could request multiple files, the result would be a reduction in latency. For example, the client would use a single HTTP exchange for an HTML document and its inlined images. Because HTTP exchanges tend to be bursty, clustering requests into a single HTTP exchange might result in a saving of resources with minimal overhead.

A related optimization would increase the asynchronicity of the exchange, allowing the server to send more than one object with out acknowledgement and to send the files out of order.

Binary encoding of headers instead of ASCII

Parsing ASCII HTTP headers is less efficient than a binary encoding would be. Using a short bitmap to cover the most common, well-known object types would cut down the negotiation packet size enormously. Additional types could be proposed by sending the option together with an encoding such as a numeric code to refer to the proposed option. This scheme supports parameterized data types such as monitor color depth, or security scheme. [Spero NG]

Extend methods and reduce CGIs

Adding new methods to the HTTP protocol would reduce the time required for inter-process communications to intra-process speeds.

CGIs (Common Gateway Interfaces) extend the capabilities of a Web server. These programs are often Perl scripts. They are interpreted instead of being compiled as C/C++ programs are.

Application Program Interfaces (APIs) are faster than CGIs.

Back to Table of Contents

Conclusion

The current state of the art in Web server performance is dynamic. Significant advances are taking place all the time. Any author who intends to write a definitive piece with up-to-date information will have to revise frequently.

Proposed improvements to the HTTP protocol: interoperability with existing servers and clients, simplicity, performance, asynchronicity (sending more than one object without acknowledgment), security, authentication, commerce, licensing and copyright protection, intermediate server caching and mirroring, logging information restrictions.

Server-side improvements are transparent

Use standalone server daemon

Use threads or pools or processes

Compile scripts

Use APIs

Use local cached files instead of file I/O.

Use a scaleable Web server architecture

Use a hierarchy of caching proxy servers.

Changes to protocol require rewriting software

Keep-Alive TCP connections

Cluster requests into one HTTP exchange and asynchronicity

Binary encoding of headers

Extend methods

Back to Table of Contents


References

[Berners-Lee 93] Berners-Lee, Tim. "Hypertext Transfer Protocol (HTTP)". CERN. Nov 1993.

[Berners-Lee 94] Berners-Lee, Tim. HTTP protocol specification, CERN. 1994.

[Blakeley] Blakeley, Michael. WebStone FAQ. Silicon Graphics, Inc. 9 Nov 1995.

[Carlton] Carlton, Alexander. SPEC Web. Standard Performance Evaluation Corporation. 15 Feb 1996.

[Chankhunthod] Chankhunthod, Anawat, et al. "A Hierarchical Internet Object Cache". University of Southern California. 6 Nov 1995.

[Cockcroft] Cockcroft, Adrian. "Watcing your Web server: How do I monitor my Web server's performance and what can I do about it?" in SunWorld Online - March - Performance Q&A. Mar 1996.

[Crocker] Crocker, David H. Standard for the Format of ARPA Internet Text Messages. Aug 13, 1982.

[Denny] Denny, Robert B. WebSite Performance Analysis. 26 May [sic] 1996 {precient, I know, but that is the date on the page.}

[Edwards] Edwards, Nigel, Owen Rees. Performance of HTTP and CGI. ANSA.

[Fielding] Fielding, Roy T., Henrik Frystyk Nielsen, Tim Berners-Lee, J. Gettys, Jeffrey C. Mogul. "Hypertext Transfer Protocol -- HTTP/1.1,". IETF. May 2, 1996.

[Katz] Katz, Eric Dean, Michelle Butler, and Robert E. McGrath, A Scalable HTTP Server: The NCSA Prototype. First International WWW Conference. Also in Computer Networks and ISDN Systems, Volume 27, September 1994, pp. 155-164.

[McGrath 2/96] McGrath, Robert E. . Measuring the Performance of HTTP Daemons NCSA. 5 February 1996.

[McGrath 95] McGrath, Robert E., Performance of Several HTTP Daemons on an HP 735 Workstation NCSA. April 1995

[McGrath 1/96] McGrath, Robert E., Performance of Several Web Server Platforms. NCSA. 22 jan 1996

[Mosedale] Mosedale, Dan, William Foss, and Rob McCool. "Administering Very High Volume Internet Services"

[Musciano 1/96] Musciano, Chuck. Tuning Unix for Web service: Focus your attention on network performance, making sure your OS can handle the volume of connections you expect" in SunWorld Online - January - Webmaster. Jan 1996.

[Musciano 2/96] Musciano, Chuck. Optimizing your http server software: Get the Web server daemon screamin'" in SunWorld Online - February - Webmaster. Feb 1996.

[Padmanaghan] Padmanabhan, Ventkata N., Jeffrey C. Mogul. Improving HTTP Latency.

[Postel] Postel, J. "Transmission Control Protocol," , RFC-793, September 1981.

[SGI] Silicon Graphics, Inc. SGI WebStone 1.1 Benchmark.

[Spero Analysis] Spero, Simon E. Analysis of HTTP Performance Problems.

[Spero NG] Spero, Simon E. HTP-NG Architectural Overview.

[Sterlicchi] Sterlicchi, John. "Benchmark for Web Servers Under Development". Web Week, v2, n3, March 1996. Mecklermedia Corp. Reprinted in Internet World. Web Week, Volume 2, Issue 3, March 1996 © Mecklermedia Corp.

[Sun] Sun. Webperf.

[Spyglass] Spyglass. Frequently Asked Questions About Spyglass Mosaic. 19 Feb 1996.

Back to Table of Contents

By James Rubarth-Lay
For LIS 385 T.6, "Electronic Distribution of Organizational Information", Spring 1996.
The University of Texas at Austin Graduate School of Library and Information Science
Date last modified: 9 May 1996