Scope of the system - Expecting about 10M active ads, with 100M clicks per ad every day, we can expect roughly about 10000 clicks per second.
The APIs will mostly be the
There will be two kinds of database that we can use here
At a high level, we would need the below components
When a user click comes in , below are the steps that are followed
Scalability
All the components like the Click Processor, Kafka/Kinesis , Flink and OLAP databases are easily scalable horizontally.
We can add more service instances for example for the click processor.
For Kafka/Kinesis, we can add more nodes.
For Flink, we can add more jobs/tasks.
For OLAP databases again, we can add more nodes.
Sharding
Sharding can be applied both at Kinesis queues and at Flink. So we can shard the queues based on the ad id. Flink can have one job per shard. That way we can optimise the parallel processors.
In case of hot shards, for example, an ad campaign by a really popular company can generate clicks to a particular shard. In order to optimise and distribute the keys across shards, we can generate a random number and append it to the Ad id, that way the raw click data for that ad can go to separate partitions. Partition key is the key to the shard here.
Choosing Stream Processing for the Click data instead of Batch Processing - this allows for more consistent real time data to be available for querying by advertisers.
In addition to the ad id, the ad placement service can generate a unique key for every ad. When the user clicks on the ad, the click processor would check if the key exists in the cache. If it does, then the click is ignored. Otherwise it is written to the Kinesis stream and the unique key is written to the cache too. the cache can be a Redis or Memcache.
To enable the reconcialtion process, we can have the raw data from Kinesis written to a S3 storage system. Spark can be used to batch process this raw data from S3 and aggregate it and compare with the stream processed data by Flink before dumping into the OLAP database.