Skip to content

hopsoft/composite_cache_store

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CompositeCacheStore 🚀

Lines of Code GEM Version GEM Downloads Ruby Style Tests Sponsors
Ruby.Social Follow Twitter Follow

Boost application speed and maximize user satisfaction with layered caching

Table of Contents

Sponsors

Proudly sponsored by

Why a composite cache?

Layered caching allows you to stack multiple caches with different scopes, lifetimes, and levels of reliability. A technique that yields several benefits.

  • Improved performance
  • Higher throughput
  • Reduced load
  • Enhanced capacity/scalability

Inner cache layer(s) provide the fastest reads as they're close to the application, typically in-memory within the same process. Outer layers are slower (still fast) but are shared by multiple processes and servers.

You can configure each layer with different expiration times, eviction policies, and storage mechanisms. You're in control of balancing the trade-offs between performance and data freshness.

Inner layers are supersonic while outer layers are speedy.

The difference between a cache hit on a local in-memory store versus a cache hit on a remote store is similar to making a grocery run in a Bugatti Chiron Super Sport 300+ compared to making the same trip on a bicyle, but all cache layers will be much faster than the underlying operations. For example, a complete cache miss (that triggers database queries and view rendering) would be equivalent to making this trip riding a sloth.

Eventual consistentency

Layered caching techniques exhibit some of the same traits as distributed systems because inner layers may hold onto stale data until their entries expire. Be sure to configure inner layers appropriately with shorter lifetimes.

This behavior is similar to the race_condition_ttl option in ActiveSupport::Cache::Store which helps to avoid race conditions whenever multiple threads/processes try to write to the same cache entry simultaneously.

Be mindful of the potential gotchas.

  • Data consistency - it's possible to end up with inconsistent or stale data
  • Over-caching - caching too much can lead to increased memory usage and even slower performance
  • Bugs/Testing - difficult bugs can be introduced with sophisticated caching techniques

Dependencies

Installation

bundle add "composite_cache_store"

Setup

Here's an example of how you might set up layered caching in a Rails application.

# config/initializers/composite_cache_store.rb
def Rails.composite_cache
  @composite_cache ||= CompositeCacheStore.new(
    layers: [
      # Layer 1 cache (fastest)
      # Most beneficial for high traffic volume
      # Isolated to the process running an application instance
      ActiveSupport::Cache::MemoryStore.new(
        expires_in: 15.minutes,
        size: 32.megabytes
      ),

      # Layer 2 cache (faster)
      # Most beneficial for moderate traffic volume
      # Isolated to the machine running N-number of application instances,
      # and shared by all application processes on the machine
      ActiveSupport::Cache::RedisCacheStore.new(
        url: "redis://localhost:6379/0",
        expires_in: 2.hours
      ),

      # Layer 3 cache (fast)
      # Global cache shared by all application processes on all machines
      ActiveSupport::Cache::RedisCacheStore.new(
        url: "redis://remote.example.com:6379/0",
        expires_in: 7.days
      ),

      # additional layers are optional
    ]
  )
end

Usage

A composite cache is ideal for mitigating hot spot latency in frequently invoked areas of the codebase.

# method that's invoked frequently by multiple processes/machines
def hotspot
  Rails.composite_cache.fetch("example", expires_in: 12.hours) do
    # reserve for high frequency access of slow operations
    #
    # examples:
    # - api invocations
    # - database queries
    # - template renders
    # - etc.

    frequently_accessed_slow_operation
  end
end

License

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

About

A composite cache store comprised of layered ActiveSupport::Cache::Store instances

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published