Like most people, I did not know much about HTTP Keep-Alive headers other than that they could be very bad if used incorrectly. So I’ve kept them off, which is the default. But I ran across this blog post which explains the HTTP Keep-Alive, including its benefits and potential pitfalls pretty clearly.
It’s all pretty simple really. There is an overhead to opening and closing TCP connections. To alleviate this, Apache can agree to provide persistent connections by sending HTTP Keep-Alive headers. Then the browser can open a single connection to download multiple resources. But Apache won’t know when the browser is done downloading, so it simply keeps the connection open according to a Keep-Alive timeout, which is set to 15 seconds by default. The problem is the machine can only keep so many simultaneous requests open due to physical limitations (e.g. RAM, CPU, etc.) And 15 seconds is a long time.
To allow browsers to gain some parallelism on downloading files, without keeping persistent connections open too long, the Keep-Alive timeout value should be set to something very low, e.g. 2 seconds.
I’ve done this for static content only. Why only static content? It doesn’t really make much sense for the main page source itself since that’s the page the user wants to view.
I’ve mentioned before that by serving all static content on dedicated subdomains, we indirectly get the benefit of being able to optimize just those subdomains. So far, this meant:
- disabling
.htaccess
files - setting a far-future Expires: header
- avoiding setting cookies on the subdomain
Now we can add to the list: enabling HTTP Keep-Alive headers. The VirtualHost
block might look like this now:
ServerName static0.yourdomain.com
ServerAlias static1.yourdomain.com
ServerAlias static2.yourdomain.com
ServerAlias static3.yourdomain.com
DocumentRoot /var/www/vhosts/yourdomain.com
KeepAlive On
KeepAliveTimeout 2
AllowOverride None
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/x-javascript "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"