At Vquence our Rails setup looks something like this.
------------ --------- ------------ | Internet |---->| Squid |---->| Mongrels | ------------ --------- ------------
(Who needs Inkscape when you have ASCII art)
This infrastructure is hosted in the US and up until recently squid hadn’t been doing much of anything except really sitting there.
Now a few months ago when we signed a contract with an Australian customer we decided we needed to place a squid cache in Australia which would actually cache content. For two reasons, firstly the US is a long way away and the 300ms latency is really noticeable and secondly because some of our pages involving graphs have long statistical calculations which can take minutes to render. (OK its really because no one has had a chance to optimise them yet but lets pretend that’s not the case). So we changed the above setup for the Australian customers to look like the following.
------------ ------------ ------------ ------------ | Internet |---->| Squid AU |---->| Squid US |---->| Mongrels | ------------ ------------ ------------ ------------
We hand out urls like http://www.client.b2b.vquence.com/widget to Australian customers and the rails backend is smart enough to make sure all the URLs look similar (I’ll blog about how I did that another time).
Without much time to look into thing properly I did some really nasty things on the AU squid cache to make sure it cached the pages.
refresh_pattern /client/graph 1440 0% 1440 ignore-no-cache ignore-reload refresh_pattern /client/static 1440 0% 1440 ignore-no-cache ignore-reload refresh_pattern /client/video 1440 0% 1440 ignore-no-cache ignore-reload
This is evil, breaks a whole heap of RFCs but it did the trick and got us out of a bind quickly.
A few weeks ago I moved the production site to Rails 2.0, I noticed around this time that the caching had stopped working. The client was no longer using our services as their campaign had finished so it wasn’t an urgent concern.
It seems that Rails 2.0 goes one step further to ensure that caches don’t cache content and instead of just sending
Cache-Control: no-cache
it now sends
Cache-Control: private, max-age=0, must-revalidate
I tried adding ignore-private, since if you’re breaking some aspects of the RFC you may as well break a couple more, but squid still refused to cache the content. After struggling with this for a bit I decided that the universe was trying to tell me I should actually do things properly.
So with squid set back to its defaults I went exploring how to accomplish this. Google wasn’t all that helpful at first since most Rails caching articles talk about caching to static files as most sites don’t implement reverse proxying for caching. It turns out however its fairly simple. In the appropriate actions in your controllers simply do the following.
class VideoController false render :template => "videos/vquence" end end
This will send the following header and cache the page for 8 hours.
Cache-Control: max-age=28800
Now everything is much faster!!
Thanks for the article.
What are you doing to handle cookies in this scenario? I’m using varnish instead of squid and I’m seeing Cache-Control being set as you said. However, looking at the cache hits, it looks like things are not being fetched from cache. I’m doing a content GET so it should be cachable.
Thanks for the post! It helped me (temporarily) solve a problem with Safari and dynamically-generated images sent with send_data in Rails 2.2.2. The images would load the first time they were requests, but on reloading, Safari would hang for a few minutes, and then timeout. I could clear Safari’s cache and the reload and the image would reload.
Using your tip (expires_in …) fixed the problem.
hi, nice post. I like the idea of using squid as a reverse proxy for thin or mongrel, but i never configured a squid and i can not find any information on how to use squid with rails. can you give me a hint where to start?
Hi Martin,
That post is fairly old now and times have moved on a little. I would explore using nginx or varnish as a reverse proxy instead.