List functional requirements for the system (Ask the chat bot for hints if stuck.)...
keys can be overwritten
values can be in any format - just a byte array
"key-level transactionality"
List non-functional requirements for the system...
100K reads/sec
10K writes/sec
read-heavy system
avg value: 1kb
highly available, low latency
tunable consensus
value size limit of 1MB
Estimate the scale of the system you are going to design...
1e3 bytes/write * 1e4 writes/sec * 3e7 sec/yr => 3e14 bytes/yr => 100TB / yr
1e3 bytes/read * 1e5 reads/sec => 1e8 bytes/sec => 100 MB/sec
Define what APIs are expected from the system...
write(key: []byte, value: []byte)
read(key)
Defining the system data model early on will clarify how data will flow among different components of the system. Also you could draw an ER diagram using the diagramming tool to enhance your design...
distribute load evenly across servers via consistent hashing
each shard has 2 replicas, across multiple regions
use gossip protocol and quorum consensus to detect failures and elect new leaders during failover
w + r > n
You should identify enough components that are needed to solve the actual problem from end to end. Also remember to draw a block diagram using the diagramming tool to augment your design. If you are unfamiliar with the tool, you can simply describe your design to the chat bot and ask it to generate a starter diagram for you to modify...
client: http client
coordinator: "partition-aware proxy" to direct the write/read to the appropriate partition
distributed databases: each running a hash table, flushing writes to disk
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
each partition will have a cache and SS table to improve durability. ie: write-ahead logging
Uses a write-through cache to leverage caching and ensure consistency between the cache and the persistent storage.
For writes, if the requested key not in memory, leverage a bloom filter to narrow down which SSTable contains the key, then look up the key in that SS Table and return the data.
Explain any trade offs you have made and why you made certain tech choices...
Tunable consistency with r + w > n
Try to discuss as many failure scenarios/bottlenecks as possible.
With replication and failover, we can fail over to a new leader when the leader goes down. Majority quorum is usually used, via algorithm like paxos or raft, to elect the new leader.
consistent hashing ensures minimal data is moved when a new server is added/removed to/from the ring
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?
Handling large key values - compression, streaming, chunking, indexing, etc