tldr: Memcached

Part of the tldr series, which summarizes papers I'm currently reading. Inspired by the morning paper.

Scaling Memcache at Facebook [2013]

Nishtala et al.

Introduction 

Although this paper does not introduce new ideas, it describes memcache, a real-world, large-scale, successful system deployed at Facebook.

Specifically, Facebook uses memcache in two ways: 
  • Query cache to lighten read load on databases. See the figure above.
  • Generic cache. For example, engineers can store pre-computed results from ML algorithms in memcached. 
The system's workload was dominated by fetching data, which steered its designers towards caching. Additionally, the reads were from a range of sources (like MySQL databases, HDFS installations, and backend services), so it had to have a flexible caching strategy. 

Memcached

The authors describe how Facebook used memcached, an in-memory key-value store running on a single server, to build a distributed key-value store. (Different from memcache, which is how they refer to their distributed system.) Memcached was a natural choice as a building block because it has a simple set of operation: set, get, and delete.  

Evolution 


The final design is shown in the figure above. Facebook evolved memcache in several stages, which we explain in the next few subsections.

Scaling within a cluster

At this point, Facebook was mostly focused on the following two goals:
  • Reducing latency of fetching cached data
    • One user web request can involve hundreds of memcache get requests. 
    • All-to-all communication between web servers and memcached servers. Items are distributed across memcached servers using consistent hashing. 
    • Parallel requests and batching. Web server uses directed acyclic graph of data dependencies to maximum number of items that can be fetched in parallel.
    • Client-server communication. Memcached servers don't communicate with each other. Thus, a memcache client on each server handles serialization, compression, request routing, etc. 
  • Reducing load imposed due to a cache miss.
    • Leases
      • Handles the issues of stale sets, which is when a web server sets a stale value in memcache. A memcached server hands a lease to a client. The lease is a 64-bit token bound to a key the client requested. The client provides the lease when setting a value in the cache. Memcached can use the lease to verify whether the data should be stored. Thus, stale sets are prevented.
      • Handles the issues of thundering herds, which is when a certain key is heavily bombarded by reads and writes. If a key's value is requested within 10 seconds of a lease being issued, the client has to wait. Then, when waiting clients retry, whichever client had the lease will have probably set the value successfully. 
      • Stale values. Sometimes, returning a slightly stale value is acceptable.
    • Pools. Since different applications result in different workloads, a cluster's memcached servers are partitioned into separate pools. 
    • Replication within pools. A category of keys within a pool is replicated if the application frequently fetches many keys simultaneously, the entire dataset fits in 1-2 memcached servers, or the request rate is higher than what one server can handle.
Facebook also used an automated recovery system to handle failures. Since there can be excessive load to backend services while the recovery procedure is running, more and more failures can appear and snowball. Thus, Facebook uses Gutter, a group of about 1% of memcached servers, to take over failed servers' responsibilities. 

Clusters within a region 

Web servers and memcached servers are split into multiple frontend clusters. Together, a frontend cluster and its corresponding storage cluster that contains the databases form a region

To reduce the number of replicas, multiple frontend clusters share the same set of memcached servers. This is called a regional pool

Conclusion

Some lessons we can learn from memcached are:

  • Caching is important for throughput, not just latency.
  • Consistency is tricky to get right.





Popular posts from this blog

Space Race: a simple Rust game built on the Bevy framework

Building a Toy Language Compiler in Go

tldr: Raft + Implementation Tips