Stop the same ip address from spamming endpoints on our system.
Latency, as we need the rate limiter that is transferring requests to be quick, otherwise it will hold up our server. Availability, our late limiter needs to either be available all the time or allow for requests to go through even when its down.
Assuming our server gets 100 million requests a month, this is roughly 3 million requests per day or 33 requests per second. If this is how many times our server gets hit, the rate limiter needs to actually be able to handle more requests, and give an error message when the same user is spamming us. lets say 1000 requests per second.
The metadata we need to store per user hitting the api is just their public ip and last time they hit the server, and the api endpoint they are trying to hit lets say on average 1 byte/character, we can estimate at about 100 bytes per user. Assuming 100 million requests and an average of 5 per user a month at least, 20 million users. 20 million * 50 bytes = 100 million bytes. So 100Mb per month, or 1.2 Gb a year.
Lets assume we have api endpoint: https://server/home. We want to hit our rate limiter before we redirect to this endpoint or any endpoint for that matter. We can return the status code of the server if we go past the rate limiter otherwise we return 429 status code for too many requests. We can set a generic rate limiter of no more than 5 requests per api endpoint every minute. For authentication api endpoints we can set a more strict rate limiter.
For the rate limiter itself we can just use a redis cache, as having temporary storage makes sense here. We want to prioritize latency, and after a minute that cache no longer matters for that endpoint and that user. Also if the rate limiter crashes and the cache gets wiped thats okay to start from a clean slate.
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...
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Explain any trade offs you have made and why you made certain tech choices...
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?