In a parking, we have a certain number of spots and we want to efficiently place new vehicles on this spot.
To simplify a customer can get a ticket that will give him a spot and also leave which frees the spot. To simplify I propose not including the payment part and assume that the customer always go to the correct spot.
Main objects are:
Spot is mutable as it can be freed when user leaves
System needs to be consistent: we don't want 2 users ending up in the same spot. Availability is less important: if a user must wait 5 second to get his ticket it is ok.
Asking for a ticket and getting it requires around 20s. Idem for giving back the ticket and leaving. We can expect around 5 vehicles arriving at the same time, which makes 1 write every 4 seconds.
There are no reads except if we implement a mechanism where users can find their spot by scanning the ticket but it should happen even less frequently.
So this is a write heavy system but the number of writes is very small. It probably will fit on one machine but we can still add replication to avoid problems
reserveSpot()
POST /spot
body: {customer information (vehicle size, for ex)}
Returns the best spot for the user, potentially calling the distribution service. Marks the spot as used
Response includes the spot id
leave()
DELETE/{spot_id}
Frees the spot (when the customer leaves)
Here the load is small and we want consistency so a standard SQL database would work
Table Spot:
spotId, isTaken, ticketId, weightLimit, overallRank (whether it is a good spot or not)
Table Ticket: tracks distributed tickets
ticketId, spotId, isValid (when marked as not valid a background process deletes them)
CLient calls the reserveSpot endpoint. He is redirected to the API gateway which calls the reserveBestSpot service. Then value is returned (client gets its ticket) and db is modified.
Client calls leave() endpoint. The api gateway redirects to the leave service that updates the db
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...
For scalability, if we need more spots, (for ex a system that actually controls several parkings), we could add sharding (shard key would be the parking id).
For availability, we could implement replication (a standard leader follower should be enough here
SQL because ACID needed. Though it can be a setback for scalability
Peak usage. As this is a write heavy scenario, a single leader may be problematic. We could instead use multi leader but it could lead to collisions which would be catastrophic. Instead, a good sharding strategy should allow to avoid the bottlenecks
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?