https://github.com/hopsoft/composite_cache_store
A composite cache store comprised of layered ActiveSupport::Cache::Store instances
https://github.com/hopsoft/composite_cache_store
Last synced: 24 days ago
JSON representation
A composite cache store comprised of layered ActiveSupport::Cache::Store instances
- Host: GitHub
- URL: https://github.com/hopsoft/composite_cache_store
- Owner: hopsoft
- License: mit
- Created: 2023-03-11T00:28:52.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-03-31T07:34:45.000Z (over 2 years ago)
- Last Synced: 2025-01-02T15:48:59.404Z (9 months ago)
- Language: Ruby
- Homepage:
- Size: 22.5 KB
- Stars: 79
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
Awesome Lists containing this project
README
CompositeCacheStore 🚀
Boost application speed and maximize user satisfaction with layered caching
## Table of Contents
- [Sponsors](#sponsors)
- [Why a composite cache?](#why-a-composite-cache)
- [Eventual consistentency](#eventual-consistentency)
- [Dependencies](#dependencies)
- [Installation](#installation)
- [Setup](#setup)
- [Usage](#usage)
- [License](#license)## 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+](https://www.bugatti.com/models/chiron-models/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](https://en.wikipedia.org/wiki/Eventual_consistency)
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`](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html#method-i-fetch-label-Options)
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
- [ActiveSupport `>= 6.0`](https://github.com/rails/rails/tree/main/activesupport)
## Installation
```sh
bundle add "composite_cache_store"
```## Setup
Here's an example of how you might set up layered caching in a Rails application.
```ruby
# 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.
```ruby
# 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](https://opensource.org/licenses/MIT).