Assumption:
Average file size: 2GB
Average user file storage: 100GB
Average file update per user: 1 per min
Total users: 1M active users
storage:
total: 100PB of data
This represents a large amount of disk storage, disregarding the replication factor (for example, RAID 10 with a minimum of four drives). This indicates we will need dedicated storage hardware to support such a large amount of data. Even considering different tiers of data storage
throughput:
100k update per minute ~ 1k rep/s
This is fairly acceptable bandwidth, might be more of a concern
bandwidth:
2GB * 100K/s = 200GB /s
This is a huge bandwidth telling us that a single data centre can't handle all the load (10GB/s internal connection is usually very high commercial). Thus the system must be geo-distributed
Define what APIs are expected from the system...
Realistically, the distributed file storage should be accessed via a drive using sys calls open, write, and close
We can also imagine a matching rest api with CRUD operations, but an RPC service might be more appropriate, especially when it comes to streaming large files.
Thus, let's define 4 commands:
Stats(file_id): retrieve file metadata
Open(file_id): lock and read, and stream the content of the file to our server
Write(file_id): upload a new version of a file (must be open first)
Close(file_id): unlock access to the file and commit the changes (if write was invoked)
Metadata Database -> SQL database storing information about the file and where it is physically stored. Sharded per user, with geo-replicated shards to prevent data loss.
Storage Nodes (Chunk Servers): A large number of simple, commodity servers that do one thing: store and retrieve chunks of data. Sharded per user, with geo-replicated shards to prevent data loss.
User/Tenant database: SQL database for handling user/tenant data and managing authentication and authorisation data.
First user will retrieve the file descriptor or metadata -> stats(fileid). This request is sent to the metadata server via the load balancer and the api gateway.
Then the user can lock and download the file to the local machine -> open(fileid), using the provided token(from the stats) request the user query will be directly routed (by the load balanceer and the api gateway) to the storage server to start the download (we can assume that the file is chunked, a multipart download or concurrent download can be done)
In short, we prefer `Direct Data Transfer` and only perform authorisation once on stats
After fetching the file, reading it and editing, the user can update the file (write(fileid)). Once again, the request is routed to the storage node via the load balancer and api gateway. The storage server
Once the user is done, the `close(fileid)` function can be used to release the lock on the file, allowing other users to read the latest version. The Storage server notifies the metadata server about the new version of the stored file.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?