Interception: Needs to intercept incoming requests to the server
Cache Mechanism:
- Cache hit: Return data from cache
- Cache miss: Retrieve data from Server, store it in cache and return data to client
Eviction: If Cache becomes full, come up with a mechanism to evict data (Ex: LRU)
Invalidation: Provide APIs to manually invalidate cache data.
Expiration: Implement TTL for cache entries
Concurrency: Needs to handle multiple reads and writes possibly to the same key
Low Latency: Return data to client with minimal latency
High Availability: Cache needs to be up all the time, so that it doesn't become a SPOF
Scalability: Needs to be able to scale according to the increasing traffic/volume
Consistency: Refresh data eventually to ensure data freshness
Since this is a Reverse Proxy, the main interface is HTTP along with Management APIs
Input: GET /resources?id=123
Headers: Cache-Control (public, max-age=3600), If-None-Match (return 304 no update), Accept-Encoding
Used by Admin for monitoring and Purging purposes
// Remove specific Key
POST /resources/purge {url: "xyz"}
// Removes all tags associated with the Key
POST /resources/purge-tags {tag: "product-updates"}
// stats like cache hit, memory usage, eviction count
GET /resources/stats
We need a high performance in memory key value store
Key needs to uniquely identify the resource
HASH (http method + scheme + host + query params)
Note: If data changes by the user (gzip, other), Accept-Encoding will also be part of the key
we will store binary content of the data and metadata to manage the lifecyle
{
"key": "1asdas313d..",
"content_binary": "asdasd",
"content_type": "text/xml",
"headers" : {
"ETag" : "asdasd565",
"Vary": "Accept-Encoding"
},
"created_at": "134523",
"expires_at": "45656",
"access_count": 50 // for LFU eviction
}
Request Coalescing
Cache stampede - If a hot key gets evicted, and multiple requests come for same key, it will bombard the Origin Server
Solution: Use SingleFit Pattern
Eviction Policy
Implement LRU using Map and Doubly Linked List
Tiered Storage
To distribute Keys across multiple Nodes, we can follow
Consistent Hashing
Benefit: We only need to remap 1/N keys on addition or deletion of a node.
Virtual Nodes
TTL (Lazy): Every Object has a max-age, Cache checks if CurrentTime > ExpiresAt before serving. Making it eventually consistent.
Conditional GET:
When TTL expires, Cache gets data from Origin on conditional basis to save bandwidth. Add header If-None-Match: