Mastering Multi‑Layer Caching in Rails with Nginx, Redis, and MySQL
This article explains six practical caching strategies—from client‑side HTTP 304 handling to Nginx static caching, full‑page, fragment, query, and database caches—using Ruby on Rails, Nginx, MySQL, and Redis to dramatically improve web application performance.
Using cache is a crucial step to improve application performance. This article summarizes various caching techniques for dynamic content using Nginx, Ruby on Rails, MySQL and Redis.
1. Client‑side cache – leverage HTTP 304 Not Modified and Rails' fresh_when method. Example:
class ArticlesController
def show
@article = Article.find(params[:id])
fresh_when last_modified: @article.updated_at.utc, etag: @article
end
endInclude user‑specific data in the ETag to avoid stale personalized pages.
2. Nginx cache – cache static‑like resources. Two approaches:
A. Turn dynamic responses into static files via an after_filter.
class CategoriesController < ActionController::Base
after_filter :generate_static_file, only: [:index]
def index
@categories = Category.all
end
def generate_static_file
File.open(Rails.root.join('public', 'categories'), 'w') { |f| f.write response.body }
end
endDelete the file on updates.
class Category < ActiveRecord::Base
after_save :delete_static_file
after_destroy :delete_static_file
def delete_static_file
File.delete Rails.root.join('public', 'categories')
end
endB. Store rendered pages in Redis and let Nginx fetch them.
upstream redis {
server redis_server_ip:6379;
}
location /categories {
set $redis_key $uri;
default_type text/html;
redis_pass redis;
error_page 404 = @httpapp;
}
location @httpapp {
proxy_pass http://ruby_backend;
}Use redis_cache.set and redis_cache.setex to manage cache entries.
3. Full‑page cache – cache entire responses with varying parameters, e.g., pagination.
class CategoriesController
caches_action :index, expires_in: 1.day, cache_path: proc { "categories/index/#{params[:page].to_i}" }
end4. Fragment cache – the most versatile. Examples for ads, article bodies, complex pages, conditional caching, and touch‑based invalidation.
- cache "adverts/#{request.controller_name}/#{request.action_name}", expires_in: 1.day do
- if advert = Advert.where(name: request.controller_name + request.action_name, enable: true).first
div.ad = advert.content
end - cache "articles/#{@article.id}/#{@article.updated_at.to_i}" do
div.article = @article.content.markdown2html
end def cache_if(condition, name = {}, cache_options = {}, &block)
if condition
cache(name, cache_options, &block)
else
yield
end
end5. Query cache – Rails query cache for a single request and gems like identity_cache or second_level_cache for cross‑request caching.
class User < ActiveRecord::Base
include IdentityCache
end class User < ActiveRecord::Base
acts_as_cached version: 1, expires_in: 1.week
end6. Database cache – summarises the six layers of caching from client to server.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
