As the lead developer of a small website constructed using Ruby on Rails, I find it a bit embarrassing to see the disappointing performance (responsiveness, memory footprint) of it. Therefore, I went to read some materials on cache to try to improve the overall experience, and this post is the summary of what I learned.

The two cache techniques I am above to discuss are HTTP cache control and fragment cache (possibly only applicable to Rails).

HTTP cache control

Don’t bother origin server

max-age is used to indicate how long an asset is considered fresh after being received from the server. If the asset is fresh, the browser is allowed to serve it without any outgoing request. Hence, it offers the fastest experience, if applicable.

public is used to indicate proxy cache servers is allowed to cache them so that request from clients could be responded by non-origin servers if they have a fresh copy of the asset.

Conditional GET

Etag is the hash of the response, so two responses having the same Etag are considered identical. This way, the browser could include Etag in its request, the server could validate the Etag to determine if the copy the client holds is still fresh. If so, mere 304 Not Modified is returned, which could potential save the bandwidth if the actual response is large.

Similar to Etag, Last-Modified is another HTTP header that could be used as the validator by the server.

Fragment cache

It’s used inside a view so that rendering could be cached, including delayed active record queries if any. This railscast does a great job explaining it.

How to do above in Rails

This railscast explains HTTP cache very clearly, and gives a few concrete examples; I am merely reprinting them.

expires_in 5.minutes, public: true # => Cache-Control: max-age=300, public
fresh_when @model # => etag and last-modifed is constructed using model
csrf_meta_tag unless response.cache_control[:public]

If there are public assets, gateway cache could be used, this is a very good read on how gateway cache works. In Rack based framework, e.g. Rails, we could use Rack-Cache as our gateway cache, then public assets could be shared by requests from different clients.

# environments/production.rb
config.action_pack.rack_cache = true