页面加载慢?可能是ref="/tag/431/" style="color:#643D3D;font-weight:bold;">缓存没用对
上周上线了一个后台报表功能,用户一多,服务器直接卡成PPT。翻日志发现数据库查询翻了十几倍,其实数据每天只变一次。这时候才想起来,Rails自带的缓存机制一直没动过。
后来加上页面缓存和片段缓存,响应时间从1.8秒降到0.3秒,服务器压力也小了。今天就聊聊我们在项目里常用的几种缓存方式,都是踩过坑后总结出来的。
页面级缓存:整页存下来最省事
适合内容变动少的页面,比如公司官网首页、帮助文档这种。开启后第一次访问生成静态文件,后续直接由Nginx返回,不走Rails。
class HelpController < ApplicationController
caches_page :show
def show
@article = Article.find(params[:id])
end
end记得在不需要时手动清除:
ActionController::Base.expire_page('/help/show/5')动作缓存:比页面缓存灵活点
页面缓存会绕过整个控制器,如果某些操作必须执行(比如权限检查),就得用动作缓存。它会走Action,但把渲染结果存下来。
class DashboardController < ApplicationController
caches_action :index
def index
authorize_user! # 这行依然会执行
@reports = Report.recent
end
end片段缓存:最常用的“局部快照”
一个页面里有些部分经常变,有些几乎不变。比如商品详情页,评论区可能每分钟都有新内容,但商品信息基本固定。这时候用片段缓存最合适。
在视图中这样写:
<% cache @product do %>
<div class="product-info">
<h1><%= @product.name %></h1>
<p>价格:<%= @product.price %></p>
</div>
<% end %>只要@product的updated_at没变,这段HTML就不会重新生成。
低层级缓存:自己控制存什么
有时候想缓存一段计算结果,比如统计某个用户的积分明细,可以用cache_store直接操作。
@rankings = Rails.cache.fetch('top_users_weekly', expires_in: 1.hour) do
User.active.order(points: :desc).limit(10)
end下次请求直接从Redis或内存读,避免重复查库。我们项目用Redis做后端,配置简单:
# config/environments/production.rb
config.cache_store = :redis_cache_store, { url: 'redis://localhost:6379/1' }缓存键的小技巧
别总用字符串当key,容易冲突。推荐用对象自动生成带版本的key:
<% cache ['v1', @article, current_user.role] do %>
...
<% end %>数组里的任何变化都会生成新key,角色不同看到的内容也不一样,自动实现多版本缓存。
上线前压测对比过,加缓存前后QPS从40涨到180,数据库连接数降了一半。合理使用缓存,不只是提升体验,还能省机器成本。