A gem for tiered Rails caching.
This lets you "stack" Rails caches: you can use a smaller, faster cache for the hotest cached items, and a larger, slower cache for more — mimicking how microprocessors commonly have a small, ultrafast L1 cache and slower L2 and L3 caches.
A common idiom is to use Rails's
memory_store
as the first level, and
mem_cache_store
or
redis_store
as the second.
If your production setup has multiple Ruby processes per server, and some free
memory on servers, it can be more sensible to run one mem_cache_store
per
server plus a shared one.
- When reading a cache key, try reading from the first level first, then go down the list: if a key is in L1 and L2, the value in L1 will be returned — honouring expiry.
- Higher levels of cache are populated when reading: if a key is in L2 but not L1, it will be added to L1.
- When writing a key, it is written to all levels.
Add this line to your application's Gemfile:
gem 'level2'
And then execute:
$ bundle
Or install it yourself as:
$ gem install level2
Level2 is configured like any other Rails cache store. Its array of options are passed to the same store lookup.
Example:
# in config/application.rb
config.cache_store = :level2, {
L1: [ :memory_store, size: 32.megabytes ],
L2: [ :mem_cache_store, 'host1.example.org:11211' ]
}
From thereon,
Rails.cache.read
and.fetch
will read fromL1
and fall back toL2
if the key is absent fromL1
.- On L1 misses and L2 hits, L1 will be populated.
Rails.cache.write
and.fetch
will write to both stores.
While discouraged, it is possible to write directly to a given cache level:
Rails.cache.write('foo', 'bar', only: :L2)
This can be useful in cases where L1
is a non-shared cache (e.g. in-memory
cache) and L2
is shared (e.g. Redis, Memcached); and you want to keep the
ability to bust the cache manually.
Level2 enriches
ActiveSupport::Notifications
.
Event payloads will include a :level
field. On cache hits, this will indicate
where the hit comes from; on misses, or any other event, the field may be
present but the value is unspecified.
Example:
# in an initializer
ActiveSupport::Notifications.subscribe 'cache_read.active_support' do |*args|
event = ActiveSupport::Notifications::Event.new(*args)
if event.payload[:hit]
Rails.logger.info "Hit from #{event.payload[:level]}"
end
end
After checking out the repo, run bin/setup
to install dependencies. Then, run
rake spec
to run the tests. You can also run bin/console
for an interactive
prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To
release a new version, update the version number in version.rb
, and then run
bundle exec rake release
, which will create a git tag for the version, push
git commits and tags, and push the .gem
file to
rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/mezis/level2.
The gem is available as open source under the terms of the MIT License.