Chapter 6

The Squid Proxy server used here has been already introduced in Section 4.5.

6.1 Considerations

The primary idea which lead the author to integrate Squid and its Server Acceleration Mode1 was to speed up large requests by taking away the part of transfering the data from the client to the server and back from the web server. According to [Wes04] there are many more benefits from this mode:

The two latter points are not taken into greater consideration in this thesis. The first point, though, fits the topic and requires a closer look.

6.1.1 Caching of whole pages

As already mentioned earlier (see Section 5.3.1), it is often difficult to cache whole pages generated by a script. A web application usually also consists of static pages that can be cached. Typically (in scripted environments) these pages are wrapped through a script in order to provide the standard navigational environments (see presentation skeleton, Section 5.4.1).

To understand, how to cache scripted pages as a whole the mechanism of a caching proxy has to be examined in greater detail.

As stated earlier, one of the top priorities of a proxy server is to be transparent to the user. So it must be ensured that no stale (=old) copy of a document is delivered to the client. To achieve this a caching proxy has to rely on the HTTP header fields sent by the servers (so called response headers).

The most important fields (also from the view of the web developer) are (compare to [Wes01]):

The Date field can be used to detect clock skews that might interfer with other date based headers. The server sends its current time which can be compared to the time on the proxy server. In our case this is somehow useless as web and proxy server reside on the same machine. If the clock is out of sync, the system might have a schizophrenic problem.

Even if the clocks of the systems are not synchronized, the Date field can still be used to convert other fields specifying absolute timestamps to relative time spans. The issue of wrong timestamps is also discussed in [Mog99].

Of greater importance is the Last-Modified field. The time of the last modification (on the server) of the document is stated here. In combination with the Date field, on the one hand, the age of the document can be determined. On the other hand, the proxy can use this timestamp to decide whether its stored copy is stale and has to be refreshed or not.

In HTTP/1.0 the request field If-Modified-Since can be used by the proxy to ask the web server about a newer version of a document [BLFF96]. If it had been changed recently, the server simply would answer with a 200 OK response and sends the new version – it acts as if there had not been a If-Modified-Since field in the request. Otherwise the 304 Not Modified message would tell the proxy that its copy is still valid.

HTTP/1.1 provides a field called Entity which can be used to establish a more complex treatment of different versions of documents (e.g. in different languages) on the server. This is discussed in great detail in [Wes01] and [FGM+99].

The Expires field provides the proxy with information about the lifetime of the document. Until this timestamp is reached, the proxy can deliver the page without revalidating it. By providing a timestamp in the past, the proxy can be told to check the file upon the next request for sure.

By using the Cache-Control header, the proxy server can be given specific information about the caching options the document has. Most important values are public vs. private which specifies whether the document contains user-specific data. In the latter case the document can only be stored in the client’s personal cache. The no-cache value advises the proxy not to store the document under any circumstances.

For a quick stale check the field Content-length can be used. If the document size stored in the cache does not match the specified one, the document is likely to have been changed in the mean time. Decisions upon this field are rather risky, though. For example content encodings (e.g. UTF-8 vs. iso8859-1) can lead to different lengths of documents of the same content.

Because of this, proxy servers usually only use this value to verify that they do not store a document that has not been transferred successfully. A client must never receive incomplete data from the proxy.

6.1.2 Programmer’s view

Knowing the headers the proxy servers rely on, the programmer has to ensure that the web application provides the proxy with the correct headers.

As mentioned earlier there are two types of documents: static and dynamic ones. While the web server commonly takes care of the correct header fields for static data – it obtains, for instance, the last modification date from the operating system – the programmer is fairly left alone with dynamic documents.

Quite an easy case is the wrapping of a static document (mixture of a static and a dynamic document – semi-static), e.g. when an HTML document is embedded with navigational elements of the site. Listing 6.1 shows how the appropriate fields can be set. This piece of code is adapted and enhanced from sample code from [Sch04].

Listing 6.1: Last modification check
2function last_modified_headers($mod_time) { 
3  $gmt_mtime = gmdate(’D, d M Y H:i:s’, $mod_time) .  GMT’; 
5  if ($_SERVER[’IF_MODIFIED_SINCE’] == $gmt_mtime) { 
6     header(’HTTP/1.1 304 Not Modified’); 
7     exit; 
8  } else { 
9     session_cache_limiter("must-revalidate");  
10     //header(’Cache-Control: must-revalidate’); 
11     header(’Last-Modified:  . $gmt_mtime); 
12  } 
14$document = static.html’; 

Note line 9: When using PHP sessions (using the command session_start) the header field Cache-Control is rewritten by PHP. When specifying a replacement value with session_cache_limiter, this behaviour can be controlled. One has to be careful with this option because sessions can affect the users privacy (see Section 2.1.2).

A problem arises when either header or footer are changed. This script will still return an old header. Either the last modification date of all three documents need to be taken into consideration (see Listing 6.2), or, simply the modification time of the static page is changed by using the command touch static.html. It depends on the application (e.g. when data from a database are retrieved in either header or footer) whether or not to choose the former method.

Listing 6.2: Last modification check adapted – pres-skel-t.php
2function last_modified_headers($mod_time) { /* code remains unchanged */ } 
4$documents = array(’’, static.html’,’); 
5$last_modification = -1; 
6foreach ($documents as $document) { 
7  if ($last_modification < filemtime($document)) { 
8     $last_modification = filemtime($document)); 
9  } 
12foreach ($documents as $document) { 
13  include($document); 

With dynamic pages it heavily depends on the content whether a time of last modification can be specified at all. Generally speaking the last modification date is the date of the “youngest” part of the page. If for a single part of the page (e.g. included content of a database) this time is unavailable, the last modification for the whole page is unavailable. This case is not unlikely.

That is the reason why caching of whole pages is problematic for dynamically generated pages. Therefore, the solution using a proxy does not suffice for web applications.

6.1.3 Expected Results

For static documents (or “statified” dynamic documents) we can expect a high gain in speed when using the caching capabilities of the proxy.

It is difficult to estimate what effect turning off a cache has. This case exactly matches the case when testing a purely dynamic script that is incapable of delivering a last modification date. A gain of speed can be expected with many concurrent requests or with slow clients.

6.2 Preparation

To prepare Squid for the server acceleration mode, the configuration file has to be modified. Squid is by default configured to be a client-side caching proxy.

This section will only give an overview of the most important options. All options that have been modified for the benchmark tests can be found in the patch file in the appendix, Listing A.2.

6.2.1 Configuring Apache

The first consideration is to have the proxy listen on the port of the web server. This is usually the well-known port 80. Before that, the web server must be told to listen on another port because only one program can occupy one port at the same time. The new port of the web server is arbitrary, the proxy server needs to be configured to forward requests to this port anyway.

The necessary change needs to be made to the file /etc/apache2/ports.
conf. The line Listen 81 will make Apache listen on port 81, instead of the default port 80.

6.2.2 Configuring Squid

For the Squid proxy server there are some more changes needed. As we have configured the web server to listen on another port, Squid should listen on port 80 instead. This is done via the command http_port 80 (see Listing 6.3).

Now we need to tell the proxy where the web server resides. This can be done using the httpd_accel_host and httpd_accel_port option. The values (=localhost via loopback interface) and 81 do the correct thing.

As with the default configuration of Squid the developers have taken care of security, there is still an option to be changed. We need to allow everyone (this is the usual purpose of a web server, opposed to the audience of a proxy) to access the proxy-accelerator. The option http_access allow all does exactly that.

These options suffice for turning on server acceleration mode. The modification of both an Apache configuration file and the Squid file requires a restart of both programs (typically done via the commands2 sudo /etc/init.d/ apache2 restart and sudo /etc/init.d/squid restart).

Still there are two more options worth considering:

The acceleration switches automatically turn off the caching-proxy function. It is be advisable to turn the function on again. This can be done via the extra option httpd_accel_with_proxy on.

When using the web server in domain virtual host mode (when more than one (sub)domain point to one IP address) the HTTP 1.1 request field Host needs to be transferred via the proxy, too. This is turned off due to security reasons once again. The appropriate option is httpd_accel_uses_ host_header on.

Listing 6.3: A reduced Squid configuration file – /etc/squid/squid.conf
53http_port 80 
1847http_access allow all 
2186httpd_accel_port 81 
2215httpd_accel_with_proxy on 
2235httpd_accel_uses_host_header on

6.3 Results

Let us now have a look at the first results.

The testings started with optimized versions of skeleton.php and pres-
skel.php (see listings 6.1 and 6.2), providing last modification headers), but without activated Squid.

For the tests there were 10,000 documents requested by the load generator, for the comparison the number of requests per seconds is taken as a measure (the total time of the test run can easily be calculated). Because static documents receive a extra ordinarily high gain of speed (compare Table 6.1 with Table 6.2), that large a number was chosen to receive representative results.

Table 6.1: Benchmarking results (Requests per second): Without Squid
Concurrent requests
File (.php) 1 5 10 25 50 100 1000

skeleton-t 78.5691.4384.6977.2469.8262.0865.91
pres-skel-t4.42 5.64 5.70 5.99 5.62 5.99 3.44*
* Aborted after 172 requests (because of a time limit of 60s per request)

6.3.1 skeleton-t.php

The (optimized) ultimate skeleton skeleton-t.php is the only page that is completely independent of a database. The results for this page are therefore quite good (i.e. fast, see Figure 6.1). This demonstrates mainly the “full power” of the server, so this is quite the upper border: 3868.6 requests per seconds with Squid turned on and 25 concurrent requests.

Table 6.2: Benchmarking results (Requests/s): With Squid
Concurrent requests
File (.php) 1 5 10 25

skeleton-t 2,500.33,590.43,868.63,788.3


6.3.2 pres-skel-t.php

This skeleton is a more realistic test candidate (see Figure 6.2). Static pages (such as the About page or the contact form of the application wrapped through a script behave very similar to pres-skel-t.php. This is only the case if the presentation skeleton stays the same upon each request – a desirable state.

Table 6.3: Benchmarking results (Requests/s): With Squid (cont.)
Concurrent requests
File (.php) 50 100 1000

skeleton-t 3,681.13,385.72,709.5


As the difference in speed is so extra-ordinarily high (and, therefore, the positive effect cannot be overlooked) we are concentrating on another aspect of high load: Concurrent requests. In the other tests we will only take a look at a maximum of 2 different concurrency rates.

Figure 6.1: Squid benchmark: skeleton-t.php

Figure 6.2: Squid benchmark: pres-skel-t.php

Figure 6.3: Squid benchmark: index.php

Table 6.4: Benchmarking results (Requests per second): index.php
Concurr. req.
Squid10 100

off 2.642.25

on 2.642.20

6.3.3 index.php

Figure 6.3 (Table 6.4) shows benchmark results of index.php with Squid turned on and off. There is no significant difference. In the case of 100 concurrent requests, turning Squid on adds so much overhead that it shows up in the benchmark.

6.4 Conclusions for Squid

Squid can accelerate static and partially static pages massively (up to the factor 420) when using the caching functionality of the proxy.

For dynamic pages Squid is no solution. It can even decrease speed due to the added overhead. This is because Squid can only cache whole pages while often no date of the last modification can be specified.

Considering even higher traffic web applications (when referring to static pages) the (disk) I/O will become a great bottleneck. [Wes04] deals with this topic and possible solutions in great detail.

For dynamic pages a proxy server does not suffice for acceleration. Therefore, more testing is necessary in the following sections.