|Read more about this book|
Whether you only run one site, or are in charge of a whole network, Squid is an invaluable tool which improves performance immeasurably. Caching and performance optimization usually requires a lot of work on the developer's part, but Squid does all that for you. In this article we will learn to fine-tune our cache to achieve a better HIT ratio to save bandwidth and reduce the average page load time.
In this article by Kulbir Saini, author of Squid Proxy Server 3 Beginners Guide, we will take a look at the following:
- Cache peers or neighbors
- Caching the web documents in the main memory and hard disk
- Tuning Squid to enhance bandwidth savings and reduce latency
(For more resources on Proxy Servers, see here.)
Cache peers or neighbors
Cache peers or neighbors are the other proxy servers with which our Squid proxy server can:
- Share its cache with to reduce bandwidth usage and access time
- Use it as a parent or sibling proxy server to satisfy its clients' requests
- Use it as a parent or sibling proxy server
We normally deploy more than one proxy server in the same network to share the load of a single server for better performance. The proxy servers can use each other's cache to retrieve the cached web documents locally to improve performance. Let's have a brief look at the directives provided by Squid for communication among different cache peers.
Declaring cache peers
The directive cache_peer is used to tell Squid about proxy servers in our neighborhood. Let's have a quick look at the syntax for this directive:
cache_peer HOSTNAME_OR_IP_ADDRESS TYPE PROXY_PORT ICP_PORT [OPTIONS]
In this code, HOSTNAME_OR_IP_ADDRESS is the hostname or IP address of the target proxy server or cache peer. TYPE specifies the type of the proxy server, which in turn, determines how that proxy server will be used by our proxy server. The other proxy servers can be used as a parent, sibling, or a member of a multicast group.
Time for action – adding a cache peer
Let's add a proxy server (parent.example.com) that will act as a parent proxy to our proxy server:
cache_peer parent.example.com parent 3128 3130 default proxy-only
3130 is the standard ICP port. If the other proxy server is not using the standard ICP port, we should change the code accordingly. This code will direct Squid to use parent.example.com as a proxy server to satisfy client requests in case it's not able to do so itself.
The option default specifies that this cache peer should be used as a last resort in the scenario where other peers can't be contacted. The option proxy-only specifies that the content fetched using this peer should not be cached locally. This is helpful when we don't want to replicate cached web documents, especially when the two peers are connected with a high bandwidth backbone.
What just happened?
We added parent.example.com as a cache peer or parent proxy to our Squid proxy server. We also used the option proxy-only, which means the requests fetched using this cache peer will not be cached on our proxy server.
There are several other options in which you can add cache peers, for various purposes, such as, a hierarchy.
Quickly restricting access to domains using peers
If we have added a few proxy servers as cache peers to our Squid server, we may have the desire to have a little bit of control over the requests being forwarded to the peers. The directive cache_peer_domain is a quick way to achieve the desired control. The syntax of this directive is quite simple:
cache_peer_domain CACHE_PEER_HOSTNAME [!]DOMAIN1 [[!]DOMAIN2 ...]
In the code, CACHE_PEER_HOSTNAME is the hostname or IP address of the cache peer being used when declaring it as a cache peer, using the cache_peer directive. We can specify any number of domains which may be fetched through this cache peer. Adding a bang (!) as a prefix to the domain name will prevent the use of this cache peer for that particular domain.
Let's say we want to use the videoproxy.example.com cache peer for browsing video portals like Youtube, Netflix, Metacafe, and so on.
cache_peer_domain videoproxy.example.com .youtube.com .netflix.com
cache_peer_domain videoproxy.example.com .metacafe.com
These two lines will configure Squid to use the videoproxy.example.com cache peer for requests to the domains youtube.com, netflix.com, and metacafe.com only. Requests to other domains will not be forwarded using this peer.
Advanced control on access using peers
We just learned about cache_peer_domain, which provides a way to control access using cache peers. However, it's not really flexible in granting or revoking access. That's when cache_peer_access comes into the picture, which provides a very flexible way to control access using cache peers using ACLs. The syntax and implications are similar to other access directives such as http_access.
cache_peer_access CACHE_PEER_HOSTNAME allow|deny [!]ACL_NAME
Let's write the following configuration lines, which will allow only the clients on the network 192.0.2.0/24 to use the cache peer acadproxy.example.com for accessing Youtube, Netflix, and Metacafe.
acl my_network src 192.0.2.0/24
acl video_sites dstdomain .youtube.com .netflix.com .metacafe.com
cache_peer_access acadproxy.example.com allow my_network video_sites
cache_peer_access acadproxy.example.com deny all
In the same way, we can use other ACL types to achieve better control over access to various websites using cache peers.
Caching web documents
All this time, we have been talking about the caching of web documents and how it helps in saving bandwidth and improving the end user experience, now it's time to learn how and where Squid actually keeps these cached documents so that they can be served on demand. Squid uses main memory (RAM) and hard disks for storing or caching the web documents.
Caching is a complex process but Squid handles it beautifully and exposes the directives using squid.conf, so that we can control how much should be cached and what should be given the highest priority while caching. Let's have a brief look at the caching-related directives provided by Squid.
Using main memory (RAM) for caching
The web documents cached in the main memory or RAM can be served very quickly as data read/write speeds of RAM are very high compared to hard disks with mechanical parts. However, as the amount of space available in RAM for caching is very low compared to the cache space available on hard disks, only very popular objects or the documents with a very high probability of being requested again, are stored in cache space available in RAM.
As the cache space in memory is precious, the documents are stored on a priority basis. Let's have a look at the different types of objects which can be cached.
In-transit objects or current requests
These are the objects related to the current requests and they have the highest priority to be kept in the cache space in RAM. These objects must be kept in RAM and if there is a situation where the incoming request rate is quite high and we are about to overflow the cache space in RAM, Squid will try to keep the served part (the part which has already been sent to the client) on the disk to create free space in RAM.
Hot or popular objects
These objects or web documents are popular and are requested quite frequently compared to others. These are stored in the cache space left after storing the in-transit objects as these have a lower priority than in-transit objects. These objects are generally pushed to disk when there is a need to generate more in RAM cache space for storing the in-transit objects.
Negatively cached objects
Negatively cached objects are error messages which Squid has encountered while fetching a page or web document on behalf of a client. For example, if a request to a web page has resulted in a HTTP error 404 (page not found), and Squid receives a subsequent request for the same web page, then Squid will check if the response is still fresh and will return a reply from the cache itself. If there is a request for the same page after the negatively cached object corresponding to that page has expired, Squid will check again if the page is available.
Negatively cached objects have the same priority as hot or popular objects and they can be pushed to disk at any time in favor of in-transit objects.
Specifying cache space in RAM
So far we have learned about how the available cache space is utilized for storing or caching different types of objects with different priorities. Now, it's time to learn about specifying the amount of RAM space we want to dedicate for caching. While deciding the RAM space for caching, we should be neither greedy nor paranoid. If we specify a large percentage of RAM for caching, the overall system performance will suffer as the system will start swapping processes in case there is no free RAM left for other processes. If we use a very low percentage of RAM for caching, then we'll not be able to take full advantage of Squid's caching mechanism. The default size of the memory cache is 256 MB.
Time for action – specifying space for memory caching
We can use extra RAM space available on a running system after sparing a chunk of memory that can be utilized by the running process under heavy load. To find out the amount of free RAM available on our system, we can use either the top or free command. To find out the free RAM in Megabytes, we can use the free command as follows:
$ free -m
For more details, please check the top(1) and free(1) man pages.
Now, let's say we have 4 GB of total RAM on the server and all the processes are running comfortably in 1 GB of RAM space. After securing another 512 MB for emergency situations where running processes may take extra memory, we can safely allocate 2.5 GB of RAM for caching.
To specify the cache size in the main memory, we use the directive cache_mem. It has a very simple format. As we have learned before, we can specify the memory size in bytes, KB, MB, or GB. Let's specify the cache memory size for the previous example:
cache_mem 2500 MB
The previous value specified with cache_mem is in Megabytes.
What just happened?
We learned about calculating the approximate space in the main memory, which can be used to cache web documents and therefore enhance the performance of the Squid server by a significant margin.
Have a go hero – calculating cache_mem for your machine
Note down the total RAM on your machine and calculate the approximate space in megabytes that you can allocate for memory caching.
Maximum object size in memory
As we have limited space in memory available for caching objects, we need to use the space in an optimized way. We should plan to set this a bit low, as setting it to a too larger size will mean that there will be a lesser number of cached objects in the memory and the HIT (being found in cache) rate will suffer significantly. The default maximum size used by Squid is 512 KB, but we can change it depending on our value for cache_mem. So, if we want to set it to 1 MB, as we have a lot of RAM available for caching (as in the previous example), we can use the maximum_object_size_in_memory directive as follows:
maximum_object_size_in_memory 1 MB
This command will set the allowed maximum object size in memory cache to 1 MB.
Memory cache mode
With the newer versions of Squid, we can control which objects we want to keep in the memory cache for optimizing the performance. Squid offers the directive memory_cache_mode to set the mode that Squid should use to utilize the space available in memory cache. There are three different modes available:
|always||The mode always is used to keep all the most recently fetched objects that can fit in the available space. This is the default mode used by Squid.|
|disk||When the disk mode is set, only the objects which are already cached on a hard disk and have received a HIT (meaning they were requested subsequently after being cached), will be stored in the memory cache.|
|network||Only the objects which have been fetched from the network (including neighbors) are kept in the memory cache, if the network mode is set.|
Setting the mode is easy and can be set using the memory_cache_mode directive as shown:
This configuration line will set memory cache mode to always; this means that most recently fetched objects will be kept in the memory.
|Read more about this book|
(For more resources on Proxy Servers, see here.)
Using hard disks for caching
In the previous section, we learned about using the main memory for caching various types of objects or web documents to reduce bandwidth usage and enhance the end user experience. However, as the space available in RAM is small in size and we can't really invest a lot in the main memory as it's very expensive in terms of bytes per unit of money. As opposed to the mechanical disks, we prefer to deploy proxy servers with huge storage space which can be used for caching objects. Let's have a look at how to tell Squid about caching objects to disks.
Specifying the storage space
The directive cache_dir is used to declare the space on the hard disk where Squid will store or cache the web documents for use in future. Let's have a look at the syntax of cache_dir and try to understand the different arguments and options:
cache_dir STORAGE_TYPE DIRECTORY SIZE_IN_Mbytes L1 L2 [OPTIONS]
Operating systems implement filesystems to store files and directories on the disk drives. In the Linux/Unix world, ext2, ext3, ext4, reiserfs, xfs, UFS (Unix File System), and so on, are the popular filesystems. Filesystems also expose a few system calls such as open(), close(), read(), and so on, so that other programs can read/write/remove files from the storage. Squid also uses these system calls to interact with the filesystems and manage the cached objects on the disk.
On top of the filesystems and with the help of the available system calls exposed by the filesystems, Squid implements storage schemes such as ufs, aufs, and diskd.
All the storage schemes supported by the operating system are built by default. The ufs is a very simple storage scheme and all the I/O transactions are done using the main Squid process. As some of the system calls are blocking (meaning the system call will not return until the I/O transaction is complete) in nature, they sometimes cause delays in processing requests, especially under heavy load, resulting in an overall bad performance. ufs is good for servers with less load and high speed disks, but is not really preferable for busy caches.
aufs is an improved version of ufs where a stands for asynchronous I/O. In other words, aufs is ufs with asynchronous I/O support, which is achieved by utilizing POSIX-threads (pthreads library). Asynchronous I/O prevents blocking of the main Squid process by some system calls, meaning that Squid can keep on serving requests while we are waiting for some I/O transaction to complete. So, if we have the pthreads library support on our operating system, we should always go for aufs instead of ufs, especially for heavily loaded proxy servers.
The Disk Daemon (diskd) storage scheme is similar to aufs. The only difference is that diskd uses an external process for I/O transactions instead of threads. Squid and diskd process for each cache_dir (of the diskd type) to communicate using message queues and shared memory. As diskd involves a queuing system, it may get overloaded over time in a busy proxy server. So, we can pass two additional options to cache_dir which determines how Squid will behave in case there are more messages in the queues than diskd is able to process. Let's have a look at the syntax of the cache_dir directive for diskd as STORAGE_TYPE
cache_dir diskd DIRECTORY SIZE_Mbytes L1 L2 [OPTIONS] [Q1=n] [Q2=n]
The value of Q1 signifies the number of pending messages in the queue beyond which Squid will not place new requests for I/O transactions. Though Squid will keep on entertaining requests normally, it'll not be able to cache new objects or check cache for any HITs. HIT performance will suffer in this period of time. The default value of Q1 is 64.
The value of Q2 signifies the number of pending messages in the queue beyond which Squid will cease to operate and will go in to block mode. No new requests will be served in this period until Squid receives a reply or the messages in the queue fall below this number. The default number of Q2 is 72.
As you can see from the explanation of Q1 and Q2, if the value of Q1 is more than Q2, Squid will go in to block mode first. If the queue is full it will result in higher latency but better HIT ratio. If the value of Q1 is less than Q2, Squid will keep on serving the requests from the network even if there is no I/O. This will result in lower latency, but the HIT ratio will suffer considerably.
Choosing a directory name or location
We can specify any location on the filesystem for the directory name. Squid will populate it with its own directory structure and will start storing or caching web documents in the space available. However, we must make sure that the directory already exists and is writable by the Squid process. Squid will not create the directory if it doesn't exist already.
Time for action – creating a cache directory
The cache directory location may not be on the same disk or partition. We can mount another disk drive and specify that as the directory for caching. For example, let's say we have another drive connected as /dev/sdb and one of the partitions is /dev/sdb1, we can mount it to the /drive/ and use it right away.
$ mkdir /drive/
$ mount /dev/sdb1 /drive/squid_cache/
$ mkdir /drive/squid_cache
$ chown squid:squid /drive/squid_cache/
In the previous code, we created a directory /drive/ and mounted /dev/sdb1, the partition from the other disk drive, to it. Then, we created a directory squid_cache in the directory /drive/ and changed the ownership of the directory to Squid, so that Squid can have write access to this directory. Now we can use /drive/squid_cache/ as one of the directories with the cache_dir directive.
What just happened?
We mounted a partition from a different hard disk and assigned the correct ownership to use it as a cache directory for disk caching.
Declaring the size of the cache
This is the easy part. We must keep in mind that we should not append MB or GB to the number while specifying the size in this directive. The size is always specified in Megabytes. So, if we want to use 100 GB of disk space for caching, we should set size to 102400 (102400 MB/1024 = 100 GB).
If we want to use the entire disk partition for caching, we should not set the cache size to be equal to the size of the partition because Squid may need some extra space for temporary files and the swap.state file. So, it's good practice to subtract 5-15 percent from the total disk space for temporary files and then set the cache size.
Configuring the number of sub directories
There are two arguments to cache_dir named as L1 and L2. Squid stores the cacheable objects in a hierarchical fashion in directories named so that it'll be faster to lookup an object in the cache. The hierarchy is of two-levels, where L1 determines the number of directories at the first level and L2 determines the number of directories in each of the directories at the first level. We should set L1 and L2 high enough so that directories at the second level don't have a huge number of files.
Sometimes we may want our cache to be in read-only mode so that Squid doesn't store or remove any cached objects from it but continues to serve the content from it. This is achieved by using an additional option named no-store with the cache_dir directive. Please note that Squid will not update any content in the read-only cache directory. This feature is used very rarely.
Time for action – adding a cache directory
So far we have learned the meaning of different parameters used with the cache_dir directive. Let's see an example of the cache directory /squid_cache/ with 50GB of free space:
cache_dir aufs /squid_cache/ 51200 32 512
We have a cache directory /squid_cache/ with 50 GB of free space with the values of L1 and L2 as 32 and 512 respectively. So, if we assume the average size of a cached object to be 16 KB, there will be 51200x1024÷(32x512x16) = 200 cached objects in each of the directories at the second level, which is quite good.
What just happened?
We added /squid_cache/ with a 50 GB free disk space as a cache directory to cache web documents on the hard disk. Following the previous instructions, we can add as many cache directories as we want, depending on the availability of space.
Cache directory selection
If we have specified multiple caching directories, we may need a more efficient algorithm to ensure optimal performance. For example, when under a heavy load, Squid will perform a lot of I/O transactions. In such cases, if the load is split across the directories, this will obviously result in low latency.
Squid provides the directive store_dir_select_algorithm, which can be used to specify the way in which the cache directories should be used. It takes one of the values from least-load and round-robin.
If we want to distribute cached objects evenly across the caching directories, we should go for round-robin. If we want the best performance with least latency, we should certainly go for least-load, where Squid will try to pick the directory with the least I/O operations.
Cache object size limits
It is important to place limits on the size of the web documents which we are going to cache for achieving a better HIT ratio. Depending on the results we want to achieve, we may want to keep the maximum limit a bit higher than the default, which is 4 MB, which in turn depends on the size of the cache we have specified. For example, if we have a cache directory with a size of 10 GB and we set the maximum cacheable object size to 500 MB, there will be fewer objects in the cache and the HIT ratio will suffer significantly resulting in high latency. However, we shouldn't keep it really low either, as this will result in lots of I/O but fewer bandwidth savings.
Squid provides two directives known as minimum_object_size and maximum_object_size to set the object size limits. The minimum size is 0 KB, by default, meaning that there is no lower limit on the object size. If we have a huge amount of storage dedicated to caching, we can set the maximum limit to something around 100 MB, which will make sure that the popular software, audio/video content, and so on, are also cached, which may lead to significant bandwidth savings.
minimum_object_size 0 KB
maximum_object_size 96 MB
This configuration will set the minimum and maximum object size in the cache to 0 (zero) and 96 MB respectively, which means that objects with a size larger than 96 MB will not be cached.
Setting limits on object replacement
Over a period of time, the allocated space for the caching directories starts to fill up. Squid starts deleting cached objects from the cache once the occupied space by the objects crosses a certain threshold, which is determined by using the cache_swap_low and cache_swap_high directives. These directives take integral values between 0 and 100.
So, in accordance with these values, when the space occupied for a cache directory crosses 96 percent, Squid will start deleting objects from the cache and will try to maintain the utilization near 96 percent. However, if the incoming rate is high and the space utilization starts to touch the high limit (97 percent), the deletion becomes quite frequent until utilization moves towards the lower limit.
Squid's defaults for low and high limits are 90 percent and 95 percent respectively, which are good if the size of cache directory is low (like 10 GB). However, if we have a large amount of space for caching (such as a few hundreds GBs), we can push the limits a bit higher and closer because even 1 percent will mean a difference of more than a gigabyte.
Cache replacement policies
In the previous two sections, we learned about using the main memory and hard disks for caching web documents and how to configure Squid for optimal performance. As time passes, cache will start to fill and at some point in time, Squid will need to purge or delete old objects from the cache to make space for new ones. Removal of objects from the cache can be achieved in several ways. One of the simplest ways to do this is to start by removing the least recently used or least frequently used objects from the cache.
Squid builds different removal or replacement policies on top of the list and heap data structures. Let's have a look at the different policies provided by Squid.
Least recently used (LRU)
Least recently used (lru) is the simplest removal policy built by Squid by default. Squid starts by removing the cached objects that are oldest (since the last HIT). The LRU policy utilizes the list data structure, but there is also a heap-based implementation of LRU known as heap lru.
Greedy dual size frequency (GDSF)
GDSF (heap GDSF) is a heap-based removal policy. In this policy, Squid tries to keep popular objects with a smaller size in the cache. In other words, if there are two cached objects with the same popularity, the object with the larger size will be purged so that we can make space for more of the less popular objects, which will eventually lead to a better HIT ratio. While using this policy, the HIT ratio is better, but overall bandwidth savings are small.
Least frequently used with dynamic aging (LFUDA)
LFUDA (heap LFUDA) is also a heap-based replacement policy. Squid keeps the most popular objects in the cache, irrespective of their size. So, this policy compromises a bit of the HIT ratio, but may result in better bandwidth savings compared to GDSF. For example, if a cached object with a large size encounters a HIT, it'll be equal to HITs for several small sized popular objects. So, this policy tries to optimize bandwidth savings instead of the HIT ratio. We should keep the maximum object size in the cache high if we use this policy to further optimize the bandwidth savings.
Now we need to specify one of the policies which we have just learned, for cache replacement for the main memory caching as well as hard disk caching. Squid provides the directives memory_replacement_policy and cache_replacement_policy for specifying the removal policies.
cache_replacement_policy heap LFUDA
These configuration lines will set the memory replacement policy to lru and the on disk cache replacement policy to heap LFUDA.
Tuning Squid for enhanced caching
Although Squid performs quite well with default caching options, we can tune it to perform even better, by not caching the unwanted web objects and caching a few non-cacheable web documents. This will achieve higher bandwidth savings and reduced latency. Let's have a look at a few techniques that can be helpful.
There may be cases when we don't want to cache certain web documents or requests from clients. The directive cache is very helpful in such cases and is very easy to use.
|Read more about this book|
(For more resources on Proxy Servers, see here.)
Time for action – preventing the caching of local content
If we don't want to cache responses for certain requests or clients, we can deny it using this option. The default behavior is to allow all cacheable responses to be cached. As servers in our local area network are close enough that we may not want to waste cache space on our proxy server by caching responses from these servers, we can selectively deny caching for responses from local servers.
acl local_machines dst 192.0.2.0/24 198.51.100.0/24
cache deny local_machines
This code will prevent responses from the servers in the networks 192.0.2.0/24 and 198.51.100.0/24 from being cached by the proxy server.
What just happened?
To optimize the performance (especially the HIT ratio), we have configured Squid not to cache the objects that are available on the local area network. We have also learned how to selectively deny caching of such content.
Refresh patterns for cached objects
Squid provides the directive refresh_pattern, using which we can control the status of a cached object.
Using refresh_pattern to cache the non-cacheable responses or to alter the lifetime of the cached objects, may lead to unexpected behavior or responses from the web servers. We should use this directive very carefully.
Refresh patterns can be used to achieve higher HIT ratios by keeping the recently expired objects fresh for a short period of time, or by overriding some of the HTTP headers sent by the web servers. While the cache directive can make use of ACLs, refresh_pattern uses regular expressions. The advantage of using the refresh_pattern directive is that we can alter the lifetime of the cached objects, while with the cache directive we can only control whether a request should be cached or not.
Let's have a look at the syntax of the refresh_pattern directive:
refresh_pattern [-i] regex min percent max [OPTIONS]
The parameter regex should be a regular expression describing the request URL. A refresh pattern line is applied to any URL matching the corresponding regular expression. There can be multiple lines of refresh patterns. The first line, whose regular expression matches the current URL, is used. By default, the regular expression is case-sensitive, but we can use -i to make it case-insensitive.
Some objects or responses from web servers may not carry an expiry time. Using the min parameter, we can specify the time (in minutes) for which the object or response should be considered fresh. The default and recommended value for this parameter is 0 because altering it may cause problems or unexpected behavior with dynamic web pages. We can use a higher value when we are absolutely sure that a website doesn't supply any dynamic content.
The parameter percent determines the life of a cached object in the absence of the Expires headers. An object's life time is considered to be the difference between the times extracted from the Last-Modified and Date headers. So, if we set the value of percent to 50 , and the difference between the times from Last-Modified and Date headers is one hour, then the object will be considered fresh for the next 30 minutes. The response age is simply the time that has passed since the response was generated by the web server or was validated by the proxy server for the freshness. The ratio of the response age to the object life time is termed as lm-factor in the Squid world.
Similarly the min, max parameters are the minimum and maximum times (in minutes) for which a cached object is considered fresh. If a cached object has spent more time in the cache than max, then it won't be considered fresh anymore.
We should note that the Expires HTTP header overrides min and max values.
Let's have a look at the method used for determining the freshness or staleness of a cached object. A cached object is considered:
- Stale (or expired), if the expiry time that was mentioned in the HTTP response header is in the past.
- Fresh, if the expiry time mentioned in the HTTP response headers is in the future.
- Stale, if response age is more than the max value.
- Fresh, if lm-factor is less than the percent value.
- Fresh, if the response age is less than the min value.
- Stale, otherwise.
Time for action – calculating the freshness of cached objects
Let's see an example of a refresh_pattern and try to calculate the freshness of an object:
refresh_patten -i ^http://example.com/test.jpg$ 0 60% 1440
Let's say a client requested the image at http://example.com/text.jpg an hour ago, and the image was last modified (created) on the web server six hours ago. Let's assume that the web server didn't specify the expiry time. So, we have the following values for the different variables:
- At the time of the request, the object age was (6 - 1) = 5 hours.
- Currently, the response age is 1 hour.
- Currently, the lm-factor is 1÷5 = 20 percent
Let's check whether the object is still fresh or not:
- The response age is 60 minutes, which is not more than 1440 (max value), so this can't be the deciding factor.
- lm-factor is 20 percent, which is less than 60 percent, so the object is still fresh.
Now, let's calculate the time when the object will expire. The object age is 5 hours and percent value is 60 percent. So, object will expire in (5 x 60) ÷100 = 3 hours from the last request, that is, 2 hours from now.
What just happened?
We learned the formula for calculating the freshness or staleness of a cached object and also the time after which a cached object will expire. We also learned about specifying refresh patterns for the different content types to optimize performance.
Options for refresh pattern
Let's have a look at the options available for the refresh_pattern directive and how they can help us improve the HIT ratio.
Please be warned that using the following options violates HTTP standards and may also cause unexpected browsing problems.
The option override-expire, overrides or ignores the Expires header, which is the main player for determining the expiry time of a cached response. As the Expires header is ignored, the values of the min, max, and percent parameters will play an essential role in determining the freshness of a response.
The option override-lastmod will force Squid to ignore the Last-Modified header, which will eventually enforce the use of min value to determine the freshness of an object. This option is of no use, if we have set the value of min to zero.
Using the reload-into-ims option will force Squid to convert the no-cache directives in the HTTP headers to the If-Modified-Since headers. The use of this option is useful only when the Last-Modified header is present.
Using the option ignore-reload will simply ignore the no-cache or reload directives present in the HTTP headers.
When the option ignore-no-cache is used, Squid simply ignores the no-cache directive in the HTTP headers.
The HTTP header Cache-Control: no-store is used to tell clients that they are not allowed to store the data being transmitted. If the option ignore-no-store is set, Squid will simply ignore this HTTP header and will cache the response if it's cacheable.
The HTTP header Cache-Control: must-revalidate means that the response must be revalidated with the originating web server before it's used again. Setting the option ignore-must-revalidate will enforce Squid to ignore this header.
Private information or sensitive data generally carries an HTTP header known as Cache-Control: private so that intermediate servers don't cache the responses. However, the option ignore-private can be used to ignore this header.
If the option ignore-auth is set, then Squid will be able to cache the authorization requests. Using this option may be really risky.
This option can be pretty useful. The option refresh-ims forces Squid to validate the cached object with the original server whenever an If-Modified-Since request header is received from a client. Using this may increase the latency, but the clients will always get the latest data.
Let's see an example with these options:
refresh_pattern -i .jpg$ 0 60% 1440 ignore-no-cache ignore-no-store reload-into-ims
This code will force all the JPEG images to be cached whether the original servers want us to cache them or not. They will be refreshed only:
- If the Expires HTTP header was present and the expiry time is in past.
- If the Expires HTTP header was missing and the response age has exceeded the max value.
Have a go hero – forcing the Google homepage to be cached for longer
Write a refresh_pattern configuration that forces the Google homepage to be cached for six hours.
refresh_pattern -i ^http:\/\/www\.google\.com\/$ 0 20% 360 override-expire override-lastmod ignore-reload ignore-no-cache ignore-no-store reload-into-ims ignore-must-revalidate
Aborting the partial retrievals
When a client initiates a request for fetching some data and aborts it prematurely, Squid may continue to try and fetch the data. This may cause bandwidth and other resources such as processing power and memory to be wasted, however if we get subsequent requests for the same object, it'll result in a better HIT ratio. To counter act this problem, Squid provides three directives quick_abort_min (KB), quick_abort_max (KB), and quick_abort_pct (percent).
For all the aborted requests, Squid will check the values for these directives and will take the appropriate action according to the following rules:
- If the remaining data that should be fetched is less than the value of quick_abort_min, Squid will continue to fetch it.
- If the remaining data to be transferred is more than the value of quick_abort_max, Squid will immediately abort the request.
- If the data that has already been transferred is more than quick_abort_pct percent of the total data, then Squid will keep retrieving the data.
Both the quick_abort_min and quick_abort_max values are in KiloBytes (KB) (or any allowed memory size unit) while quick_abort_pct is a percentage value. If we want to abort the requests in all cases, which may be required if we are short of bandwidth. We should set quick_abort_min and quick_abort_max to zero. If we have a lot of spare bandwidth, we can set a higher values for quick_abort_min and quick_abort_max, and a relatively low value for quick_abort_pct. Let's see an example for a high bandwidth case:
quick_abort_min 1024 KB
quick_abort_max 2048 KB
Caching the failed requests
Requests for resources which doesn't exist (HTTP Error 404) or a client doesn't have permission to access the requested resource (HTTP Error 403) are common and requests to such resources make up a significant percentage of the total requests. These responses are cacheable by Squid. However, sometimes web servers don't send the Expires HTTP headers in responses, which prevents Squid from caching these responses. To solve this problem, Squid provides the directive negative_ttl that forces such responses to be cached for the time specified. The syntax of negative_ttl is as follows:
Previously, this value was five minutes by default, but in the newer versions of Squid, it is set to zero seconds by default.
In this article we covered caching in the main memory and hard disk in detail. We learned about using RAM and disks for caching in an optimized manner to achieve higher HIT ratio. We saw how to fine tuning the cache.
- VirtualBox 3.1: Beginner's Guide [Book]
- Squid Proxy Server: Tips and Tricks [Article]
- Squid Proxy Server 3: Getting Started [Article]
- How to Configure Squid Proxy Server [Article]
- Configuring Squid to Use DNS Servers [Article]
- Different Ways of Running Squid Proxy Server [Article]