Addressing Cache Anomalies and Advanced Redis Mechanisms
Cache Anomalies
- Cache Penetration: Requested data does not exist in the system.
- Cache Breakdown: A hot key expires.
- Implement mutual exclusion locks.
- Apply logical expiration (no actual TTL set).
- Cache Avalanche: Numerous keys expire simultaneously.
- Assign random expiration times.
- Deploy a Redis cluster.
Cache Penetration
- Definition: Occurs when queries target non-existent data. The cache misses, each request hits the database, and since the data is absent there too, no cache entry is created for future requests.
- Solutions:
- Cache invalid keys with a placeholder value (e.g., null or a default). Subsequent requests read this placeholder from the cache, avoiding database queries.
- Employ a Bloom filter to pre-check data existence before querying.
- Bloom Filter Overview:
- A probabilistic data structure that tests set membership.
- Consists of a large bit array and multiple hash functions.
- To add an element, compute its hash values and set corresponding bits to 1.
- To query, compute hashes and check bits; if any bits 0, the element is definitely not in the set.
- False positives are possible due to hash collisions. Adjustable parameters like array size control the false positive rate, typically kept below 5%.
Cache Breakdown
- Definition: Happens when a highly accessed key expires, triggering numerous concurrent requests to fetch it from the database, potentially overwhelming it.
- Contrast with cache penetration: here, the key exists in the database but is missing from the cache due to expiration.
- Solutions:
- Mutual Exclusion Lock: Ensures strong consistency, suitable for high-security scenarios like financial transactions, but may impact performance. Only one thread accesses the database to rebuild the cache while others wait.
- Logical Expiration: Maintains high availability but may serve stale data. Store hot data without a TTL, using a field to mark logical expiration. When a thread reads data, it returns it immediately. If logically expired, it acquires a lock and spawns a background thread to refresh the cache asynchronously.
Cache Avalanche
- Definition: Caused by mass cache expiration or Redis node failure, leading to a surge in database load.
- Differs from cache breakdown in scale: many keys expire at once versus a single hot key.
- Solutions:
- Add random offsets to expiration times to stagger key expiry.
- Use Redis clustering to provide redundancy and fault tolerance.
Redis Clustering
- Ensuring High Availability:
- Clustering allows failover when nodes fail. Redis supports three main schemes: master-slave replication, sentinel mode, and Cluster sharding.
- Master-Slave Replication: Implements read-write separation with one master (writes) and multiple slaves (reads). Data sync occurs from master to slaves. Manual intervention is needed for master failover.
- Sentinel Mode: An enhanced master-slave setup with automated failover. Sentinel nodes monitor the cluster and elect a new master if the current one fails, ideal for read-heavy workloads.
- Cluster Sharding: Distributes data across multiple master nodes to handle large datasets and high write throughput. Each master can have replicas, and nodes communicate via gossip protocols. Clients can connect to any node, with requests routed appropriately.
Master-Slave Replication
- Data Synchronization Process:
- Connection Establishment: A slave sends a sync request with replication metadata (ID and offset). If it's the first sync, the master shares its metadata and initiates full replication.
- Full Replication: The master performs a background save (bgsave) to generate an RDB file, sent to the slave. The slave clears old data and loads the RDB. During this, write commands are buffered in a replication backlog.
- Incremental Replication: After full sync, a persistent TCP connection streams subsequent write commands from master to slave.
- Handling Slave Disconnection:
- Upon reconnection, incremental replication syncs missed commands. Each slave maintains a replication buffer; offsets track progress to resume sync accurately.
- Replication Model: Asynchronous by default, balancing performance and consistency.
Sentinel Mode
- Monitoring Mechanism: Sentinels ping nodes every second. Failure to respond triggers a subjective down status.
- Reducing False Positives: A cluster of at least three sentinels uses voting to confirm an objective down status before initiating failover, with a leader elected for the switch.
Cache-Database Consistency
- Synchronization Approach:
- For scenarios with moderate consistency needs and low concurrency, update the database first, then invalidate the cache (e.g., using @CacheEvict). Subsequent queries repopulate the cache with fresh data via @Cacheable.
- Drawback: Stale reads may occur if a thread reads old data from the database and populates the cache after another thread updates the database and deletes the cache.
- High-Concurrency Strategies:
- Delayed double deletion: Delete cache, update database, wait, then delete cache again to handle timing issues. Not strongly consistent.
- Read-write locks: Use tools like Redisson for higher consistency.
- Delayed Double Deletion Details:
- First deletion prevents stale cache hits during updates. The second deletion, after a delay, removes any cache entries written with old data during the update window. Timing the delay is challenging, and deletion is preferred over direct cache updates for efficiency.
Redis Persistence
- RDB (Redis Database Backup): Snapshots of data.
- Uses bgsave and copy-on-write.
- AOF (Append Only File): Logs of write commands.
- Includes rewrite mechanisms.
RDB
- Mechanism: Saves a binary snapshot of memory at a point in time, default in Redis versions before 4.0.
- Triggers:
- save command: Blocks the main process.
- bgsave command: Forks a child process to write the snapshot, allowing the main process to continue.
- Configuration-based auto-triggers in redis.conf.
- Execution via Fork:
- The fork() call creates a child process sharing the parent's memory via page tables. The child writes data to an RDB file.
- Copy-on-Write (CoW):
- During RDB creation, memory pages are read-only. If the parent modifies data, it copies the affected page to a new location, ensuring the child's snapshot remains consistent.
AOF
- Overview: Appends each write command to a log. Recovery replays these commands. Enabled via redis.conf with configurable flush policies.
- Rewrite Strategy: To prevent file bloat, bgrewriteaof triggers a rewrite that condenses commands by keeping the latest per key, written to a temporary file before replacement.
- RDB vs. AOF:
- RDB files are smaller and faster to load, but may lose data between snapshots.
- AOF offers better durability with configurable flush intervals, at the cost of larger files and slower recovery.
Hybrid Persistence
- Default in Redis 4.0+: Combines RDB and AOF. During AOF rewrite, an RDB snapshot is written at the file start, followed by incremental AOF commands. This speeds up restarts by loading the snapshot first, then replaying recent commands.
Expired Data Deletion
- Strategy: Combines lazy deletion (check on key access) and periodic deletion (background scans).
Eviction Policies
- Handling Full Memory:
- Default noeviction rejects writes. Set eviction policies like allkeys-lru or allkeys-lfu to remove data.
- LRU (Least Recently Used): Evicts keys not accessed recently, prioritizing recent usage.
- LFU (Least Frequently Used): Evicts keys with low access frequency, prioritizing high-frequency data.
- Hot Data Caching: Use LRU to retain frequently accessed keys in a limited cache (e.g., 200k entries out of 10 million).
Distributed Locks
- Need: In distributed systems, local locks don't ensure mutual exclusion across processes. Distributed locks coordinate access to shared resources.
- Implementation with Redis:
- Use SET with NX and EX options for atomic lock acquisition and expiration setting.
SET lock_key unique_value NX EX 10
- Release lock via Lua script to verify ownership before deletion, preventing accidental releases.
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
- Expiration prevents deadlocks from crashed services.
- Lock Renewal: For long operations, use frameworks like Redisson with watchdog threads that auto-extend lock expiry.
Redisson
- Automatic Renewal: A watchdog thread periodically renews the lock if the business logic is still executing, defaulting to checks every 10 seconds for a 30-second lock.
- Reentrancy: Supports reentrant locks using a hash map keyed by thread ID with a counter for lock depth, ensuring threads can re-acquire their own locks.
Performance Factors
- In-Memory Operations: Direct memory access speeds up data handling.
- Single-Threaded Design: Avoids context switching and thread-safety overhead, with separate threads for background tasks like AOF flushing.
- I/O Multiplexing: Uses non-blocking I/O to handle multiple connections concurrently in a single thread, reducing latency from network waits.
- Single-Threaded Nature: The main thread processes commands, while background threads manage auxiliary tasks to prevent blocking.
- I/O Multiplexing Explained: Instead of blocking per connection, the thread monitors multiple sockets, processing requests as they arrive, optimizing network throughput.
Tags:
Redis
Caching
database
Performance
Distributed Systems
Posted on Fri, 15 May 2026 18:47:14 +0000 by tekkenlord