Skip to content

mezis/level2

Repository files navigation

Level2 Build Status Gem Version

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.

Behaviour

  • 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.

Installation

Add this line to your application's Gemfile:

gem 'level2'

And then execute:

$ bundle

Or install it yourself as:

$ gem install level2

Usage

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 from L1 and fall back to L2 if the key is absent from L1.
  • 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.

Notifications

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

Development

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.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/mezis/level2.

License

The gem is available as open source under the terms of the MIT License.

About

Multiple caching levels for Rails. Kinda like your CPU's L1/L2 caches.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published