Estimate the scale of the system you are going to design...
Given that we are leveraging an external API, having Rest calls for typical requests alongside sockets or SDKs like Firebase that are available for emergency notifications would be ideal.
The primary API call would be the following REST API endpoing
GET /batch-weather
{
locations : [
{
city: ""
country: ""
},
]
}
This endpoint can be used to obtain data for a series of locations depending on how many places a user has subscribed to.
A secondary endpoint can be used to retrieve weather for a specific location that a user is looking up, or for the user's direct current location.
GET /weather?long=""&lat=""
This one will be specifically given details from whatever location a user is attempting to search up directly.
The client will
We are going to have to have a design where a client would first hit Rate limiter and then the load balancer which would redirect our request to the appropriate application server based on the RR stateless algorithm.
The application server would first check if the url is present in our in-memory cache (which we would know based on the cache server id based on the cache client daemon running on the application server which uses consistent hashing to determine which cache server to check. Cache is LRU
If we get the hit, we return right there. Else, we would want to check out the database. (Key-value store). NoSQL database would be able to route the request to the correct partition and return the request. If not present, we return 404.
Overall, I am okay if immediately after the resource is added, it takes a while for it to be fully propagated to all replicas (eventual consistency is OK). However, we do want to keep durability (making sure we don't lose the write request) and latency (making redirect as quickly as possible <20ms)
The writing flow is similar but with some details explained below.
For the end to end flow, a user will make an unauthenticated HTTPS request to the service. They'll send along their longitude and latitude coordinates in the GET request. A stateless server will accept the request and make a read-through request to Redis. If there is fresh information in the cache. If there's a data point in the cache that is within the acceptable range of a user's location, then we will return the data to the server. The server can then return this data directly to the user.
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...
Our reliance on the external API is a single point of failure. If the external API goes down, our service goes down as well.
The user request volume is a potential bottleneck as well if there's a burst of traffic that our servers won't be able to handle.
If we hit the weather API rate limit, we can consider serving users weather information close to location they requested. For example, we can consider a radius of 1 mile from the requested location as information that's accurate enough and serve that information to users. We can also consider leveraging multiple weather providers so we have fallback options in case one fails.
We can leverage DNS routing to route users to their closest geographical weather service. This will help alleviate the user request volume. We can consider replicating more services in dense, metropolitan areas to accommodate for areas that might experience higher volume of requests.
We will integrate the service with logging capabilities so we are able to alert on server and general region unavailability.