Of course there are many other requirements such as preview, collaboration, and so on. But I will start with these requirements.
Key Points:
200M DAU
Each person reads twice a day, writes once a day.
Average file size: 1MB
20M new files generated per day
20TB new files per day.
In two years, it would be 14.6PB of data
Rough Idea:
All APIs return HTTP error codes.
One approach is to store files in a block store, such as Amazon Elastic Block Store (EBS), to store file contents. It would be scalable.
A storage like EBS should allow updating individual blocks (chunks).
Metadata would exist:
I would store this in a relational database. Size will be in the comfort zone of RDB. Having ACID consistency for metadata would be highly desirable.
It would be smart to use CDN. Not all, but some files will show "write-once, read many times" characteristics. For example, a famous person uploads some announcement and shares it with many users. In such a case, CDN would cache this file. The many users who read it would access the copy in the CDN, instead of hitting the origin service.
An important design aspect is splitting up a big file into multiple chunks (e.g. 4MB each chunk). This would:
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...
Write path consists of:
Read path consists of:
Services are split in a way:
Data replication:
Data partition:
API Gateway authorizes user's access requests via OIDC. The client would present OIDC scopes it has. API GW makes sure the scope is enough to grant access to the files.
*** Algorithm:
One of the most important aspects is to make sure files are uploaded correctly, and stay accurate.
*** Offline work
Another important consideration is supporting offline work by client.
If client goes offline, let's say for 4 hours, the user still would like to keep working on the file. (E.g. writing a document on an airplane.).
To do this, client should store all the chunks that make up the whole file. Each chunk should have a version number.
When the client detects it becomes online after some time, it connects to the server and check:
If either client or server has updated a file, while the other party has not, then the first party should send the updated chunks (we can tell by version numbers) to the other party.
If both sides updated the document, this is a conflict, and it has to be resolved.
As a general purpose file system, our service may not be in a great position to provide an automatic conflict resolution algorithm. Doing so would require domain specific algorithm.
Therefore, by default it should support letting the user know a conflict has happened (e.g. making file name appear on the client in bright red), and giving user an option to adopt the version on the server or the version on the client.
Another interesting trade-off is privacy vs data privacy.
Privacy laws require that users can delete their data completely.
However, to be able to recover data from a disaster, it's important that the files are copied for backup in multiple places.
We need to have a consistent and accurate index so that we can find all the copies. Such a data should be stored in a RDB for high consistency.
Try to discuss as many failure scenarios/bottlenecks as possible.
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?