Estimate the scale of the system you are going to design...
POST /set&key=<key>
GET /get&key=
POST /set/conditional&key=
DELETE /&key=
Database design is not necessary as the data will be represetned as a hash map in moemry with values residing on disc
|System contains of the following elements:
1) Cluster coordinator - a node responsible for coordinating read/write requests among replica nodes
2) Cluster node - a part of the cluster that handles read and write requests, can be elected as a new coordinator
Each cluster node is a self sufficient element of the cluster and can take the role of a coordinator if needed thats why it contains the following parts:
1) Monitoring system - monitors for failures
2) Client API - and api to accept read/writes from client in case this node is elected a coordinator
3) Bloomfilter - a data strctureu to quikcly check the presence of a key on disc
4) Self repair and replication modules - self explanatory
5) Memory log - records data before flushing it to disc, also known as a write ahead log
6) Disc - tape disc to permanenly store data
The diagram is on the high level design. This is the request flow in high level.
1) Before any requests can come in a cluster elects a coordinator using gossip procotol whre each node votes for a new coordinator
2) When coordinator is elected is starts to accept requesst from a client
3) Depending on the consistency and avaialblity settings when a new requests comes in coordinator waits for a predetermined number of replica acks before signalling that request is complete. We use the following formula to provide consistency guarantee:
R + W > N - strong consistency, where R - number of read acks, W - number of write acks, N - number of nodes in the cluster
R + W <= N - weak consitency
Replica in/out flow:
1) When replica node wants to exit a cluster voluntarily or by failure the coordinator keeps a consistency hashing ring which rebalances data across multiple nodes. In case of key change new node is placed (or removed from) on the ring and some portion of the data has to be rebalanced
Replica health check:
1) To maintanin a view of healthy nodes each node has a list of neighbours that ite periodically checks using a heartbeat protocol
2) The list of neighbours is formed randomly and has a fixed length to not flood the noetwork
3) If the node doesn't respond withing a time frame it is considered offline and it's stauts is propagated to every node using gossip protocl and eventually to a coordinator node which removes it's from a consistency hashing ring
4) If 2 or more nodes agree on a particular node being offline the node is marked as an offline by a coordinator
Conflict resolution for read/writes
1) We use a vector clock approach where every data written to a replica has a version number associated with it (a clock value)
2) We 2 or more read/write requests come from a different replicas at the same time we can check if their versions have a conflict and apply a dedicated conflict resolution startegies like last write wins or resolve manually to resolve the conflict
3) Read conflicts are at teh mercy of the client and our read response always gives back a vector clock value if multiple replicas are involved
Writing data on disc
1) Evey replica contains an in-memory write ahead log that is populated first and if it becomes full the data is lfushed to disc. This is done ti have to batch write requests to disc as writing small chunks of data will influence disc write latency
Reading data from disc
1) The oS kernel caches aggresively any data read from disc in memory and thus it's out first read area when issuing |GET /key
Every replica node is self sufficient in a sense that it can take the role of a coordinator at any time it contains:
We choose distributed system with a dedicated coordinator module to provide strong constiency in distributed environment and also to make client API easier
We choose consistent hashing to decrease the number of data transfer between replicas when their numbers change
We choose merkle trees to check if any data is corrupted on disc
We choose vector clock as the easiest way to hadle conflicts in a distributed system and limit the number of clock history to prevent memory overflow
We use write-ahead memory log to batch disc writes before flushing them to disc
We use bloom filter to perform a quick check of the key in memory before performing a disc seek
When cache becomes full we LRU strategy to evict nodes and make space
When the node fials to acknowledge read or write request with use a limited exponential backoff to retry the operation
Using the formular R + W > N we can control what system is optimized for, for examepl:
if R = 1, the sytem will be optimized for reads as only 1 read acks will be neaded for read operation to be successfull
if W = 1, the system is optimized for writes in the same manner
if R + W > N, we get strong consitency model
if R + W <=N we get a weak consitency model
To balance the load on the hash ring with duplicate our nodes and call the virtual nodes, meaning that the range of requests will be mapped to the same node instead of a different node every time
To make writes durable we repliate data on W nodes where W is a configurable parameter
To handle coordinator overload we can use a rate limiter installed in every replica or use a multi coordiantor setup behind a dedicated load balancer service.
For a geo replicated data we can position our replicas close to the expected clients location
In case of a data not fitting a single node we can split data into chunks a nd store chunks as a spearate key value pairs
In case of netwrok partiiong the system will serve requests based on the existing nodes and when the ystem will get back up using the gossip protocol the data will be synchronized between the remaining nodes
Potentially to store an asbolutely huge files we can use an external blob storage and store links to it in our database instead of values
In case of a replica crash it's neighbours will get a heartbeat timeout everntually and will propagate it's status to a coordinator (eventually) so that it can remove it from a hash ring
If the replica becomes overloaded it can start replying with 429 too many requests and submit it's status to a coordinator to spin up a new replica to handle the load
In case of a frequent replica entering/leaving the cluster a system can be temporarily overloaded with a coordinatorinon/rebalance messages
In case we setup heartbeat protocol for every replica to check for every neighbour the system can become overloaded with a lot of heartbeat messages
1) user centralized log aggreagtor to monitor the system
2) Use ML with centralized nodes to predict the future load on the system and scale accordingly
3) Use adaptive stragety based on monitored data to predict what replica might crash soon or get overloaded