Scalability:
The system must support horizontal scaling to handle high QPS and traffic spikes (e.g., viral videos).
This includes:
Idempotency:
Duplicate events (e.g., retries) must not lead to over-counting.
Latency:
Video
GET /v1/video/{id}/views
GET /v1/video/{id}
ā Returns current aggregated view count
Report
GET /v1/report/video/{id}/views?start={}&end={}&breakdown=age,device,country&channel=web,app&granularity=[hourly/daily/monthly]
When a user view the video
The frontend batches raw events and sends them periodically using regular HTTP requests.
Additionally, it can use navigator.sendBeacon() to flush any remaining events when the user leaves the page.
POST /v1/events, request: {eventObj}
{
events:[
{event}
]
}
In this design, I separate the system into an online serving path and an analytics path.
For the online path, user requests go through the API Gateway, which handles routing, rate limiting, and fraud detection. Then the request goes to the view service, which updates or reads the latest view counts from View DB. This path is optimized for low-latency access to current counts.
For the analytics path, I use a separate report service. View events are streamed through Kafka, processed by Flink, and written into Druid through an aggregated pipeline. This supports near-real-time reporting queries. For longer-term analytics such as hourly, daily, or monthly trends, a Batch service writes results into a dedicated report DB.
Finally, I add Redis with a Cache Writer to accelerate common real-time report queries, especially for low-cardinality dimensions. This reduces query latency and protects the analytical backend from repeated hot queries.
To control ingestion latency and throughput, I would tune: