Solid Cache 入门:用数据库做 Rails 缓存
Solid Cache 是 Rails 7.1 引入的数据库缓存方案,用磁盘换内存,挑战 Redis 缓存的传统地位。本文讲解其原理、适用场景、实施步骤、性能优化与从 Redis 迁移的路径。
Solid Cache 把缓存存进数据库(而非内存),利用 NVMe 磁盘的高性价比实现"更大、更久的缓存"——可评估更大的缓存工作集,但容量、命中率和数据库负载需一起测量。读多写多、缓存数据量大、想精简中间件的 Rails 7.1+ 应用都值得评估它。
缓存的第一性原理
缓存的本质是空间换时间:把计算过的结果存起来,下次直接取。传统方案 Redis/Memcached 把数据放内存——快,但内存贵,容量受限,缓存一满就要逐出(eviction),命中率被容量天花板压制。
Solid Cache 的逆向思维
Solid Cache 问了一个反常识的问题:缓存一定要放内存吗? 现代 NVMe SSD 的随机读取已达微秒级,比内存慢但远比"重新计算"快。把缓存放进数据库后获得三个红利:
- 容量近乎无限:磁盘成本是内存的零头,缓存可以从 GB 级到 TB 级;
- 超长 TTL 成为可能:缓存项可以放几天几周不被逐出,命中率显著提升;
- 少一个中间件:不用部署维护 Redis 集群,备份、高可用直接复用数据库体系。
什么时候适合用它
适合:Rails 7.1+ 项目;缓存读写量大但单次延迟要求不是极端苛刻(亚毫秒级)的应用;希望缓存"大而久"提升命中率的场景(HTML 片段、API 响应、计算结果)。不适合:对延迟极端敏感的热数据(会话、限流计数器)、已深度使用 Redis 特有数据结构(Sorted Set、Pub/Sub)的场景——那些 Redis 仍是正解。
实施步骤
bin/rails solid_cache:install:migrations
bin/rails db:migrate
# config/cache.yml
production:
database: cache
store_options:
max_age: <%= 2.weeks.to_i %>
namespace: <%= Rails.env %>
# config/environments/production.rb
config.cache_store = :solid_cache_store
生产建议用独立的 cache 数据库(Rails 的多数据库支持),与主库隔离负载。
应用层用法与优化
用法与任何 Rails 缓存后端完全一致:
Rails.cache.fetch("user/#{user.id}/stats", expires_in: 12.hours) do
user.expensive_stats_calculation
end
优化要点:批量读写用 read_multi/write_multi 减少往返;给缓存键设计好命名空间方便按前缀清理;Solid Cache 默认后台线程异步清理过期项,max_age 控制硬上限,配合 cluster 配置可读写分离。
从 Redis 迁移的路径
迁移无需停机:先在双写模式过渡(部分 gem 支持,或自定义 wrapper 同时写两个后端、读新后端失败回退旧后端),观察命中率达标后切全量,最后下线 Redis 缓存实例(注意保留 Redis 给 Sidekiq 等其他用途的部分)。
验证 Solid Cache 的命中与存储成本
Solid Cache 把缓存压力放到数据库上,因此需要同时检查命中效果、缓存表增长和数据库负载。观测云可采集底层数据库指标,并通过已插桩的 Rails 请求观察 SQL 耗时;缓存命中、未命中和清理任务结果需另行埋点或记录日志。按同一业务路径比较启用前后的接口延迟,才能判断增加缓存容量是否抵消了数据库访问开销。
接入文档:PostgreSQL 采集 · Ruby APM 接入 · 监控器与告警策略。
常见问题(FAQ)
Q:Solid Cache 和 Redis 缓存性能差多少?
Redis 与数据库缓存的延迟差异取决于拓扑、负载和数据大小。比较时应记录命中率、端到端请求延迟和存储成本,而不是套用固定速度倍数。
Q:缓存表会不会把主库拖垮?
缓存是高频读写负载,建议独立数据库(甚至独立实例)部署;Solid Cache 的设计(append-mostly、后台批量清理)对数据库友好,MySQL/PostgreSQL 都能胜任。
Q:Rails 7.0 或更早版本能用吗?
Solid Cache 是独立 gem(rails 7.1+ 官方集成),老版本可手动添加 gem 使用,但多数据库等配套体验以 7.1+ 为完整,升级 Rails 是更顺的路径。
参考文档
本文依据公开文档整理,示例需按项目依赖版本验证;不将文档中的性能描述视为本项目实测结果。