assume 500M DAU, each clicks 5 ads daily. each clicks generates 1kb data.
TPS: 500M * 5 /24/3600= 29000 TPS
Storage: 500M * 5 * 365 * 1kb = 912.5TB/year
The aggregated data is related to time, read write heavy, we can use a time-series database.
The raw data is write heavy, but not read heavy since it's mainly used as a backup. We can choose NoSQL to optimize the write performance.
raw data
aggregated data - count by minute
aggregated data - top clicked ads
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...
Aggregate service
We can use map reduce to aggregate the events. We have two use cases.
For use case 1, for an aggregation service node, we internally have a mapper that distributes events to different workers, the workers aggregates the count by ad_id, then the reducer calculates the total count for each ad.
For use case 2, for an aggregation service node, we internally have a mapper that distributes events to different workers, the workers aggregates the count by ad_id, calculates the local top 100 ads, then the reducer calculates the global top 100 ads.
To scale up, we can have a zookeeper manages a set of aggregation service, ads are routed to different aggregation service based on id range.
Late arriving events
Events can arrive late in async flows, to handle that, we uses watermark, which slightly extends the window size to accomodate for events arrive late. We can also add a reconciliation service to compare the raw data and aggregation data to fix any problems.
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?