System requirements
Functional:
Parking spot management: the administrator of the parking should be able to manage parking lots by distributing parking spots for each floor of the parking spot.
Check availability: The user can check parking spot availability in real time based on the type of the vehicle: big size as truck, normal size, small size and handicapped places.
Spot assignment: The system should assign a spot based of the type of the vehicle , type of spot wanted, the desired time.
Fee calculations: The system should handle different types of rates based on the rates established by the parking lot administrator, e.g. peak hours may have a higher price. Being late to pick up the car will result in penalties
The user should be notified when the parking lot reservation or assignment will end.
The user will see in real time when places will become available or is occupied.
Payment: the user will be able to pay the calculated paid amount of the fee using his mobile app or scanning the fee.
The seat availability will be updated real time upon vehicle exit.
Non-Functional:
Consistency: services like parking lot administration, parking lot assignment, fee calculation and payment will favor strong consistency and network partition
Availability: The availability service and can be eventual consistent favoring the scalability and availability over consistency.
Reliability: the system will have different types of monitoring and alerting. The system will have logs and will implement different types of fault tolerance.
Security: different types of users will the application The access will be granted implementing RBAC using OpenId or OAuth2 protocol for authentication and authorization.
Capacity estimation
Will suppose the system has to handle 100 of parking lots each having 200 of parking spots. Will assume that each parking spot will have 100 customers daily resulting in 10K seat assignment daily.
Availability is checked by 200 customers daily resulting in 20K read requests daily.
API design
-> checkAvailability:
- input: parkingLotId, userId(to determine vehicle type)
- output: list of available parking spots available, and the number
-> assignParkingSpot:
- input: userId for vehicle type and details, desired time
- output: floor and spot number, details where to find the exit
-> feeCalculation:
- input: parkingSpot, time interval, userId
- output: detailed item list of the fee calculation: time for foreseen time, time of not foreseen, penalties.
-> payment:
- input: feeId, userId
- output: paymentId, payment date
Database design
In a reservation system an strong consistency database is needed to avoid double reservations, by using locking mechanism, like optimistic locking to prevent adding overlapping time ranges for the same parking spot. An index on the reservations table will help with retrieving fast and also for locking CREATE INDEX idx_reservation_time ON reservations(spotId, startDatetime, endDateTime). PostgreSQL for instance support exclusion constraints which can be used to prevent overlapping booking for the same reservations
erDiagram
ParkingLot ||..|{ ParkingSpot: has
ParkingSpot ||--|{ Reservation : belongs
Reservation ||--|| Vehicle: has
User ||--o{ Reservation : "can make"
User ||--|{ Vehicle: "owns"
Ticket ||--|| User: "has"
Ticket ||--|| Reservation: "based on"
Payment ||--|| Ticket: "based"
High-level design
Load balancer: used to distribute traffic using Round Robin or Weighted Round Robin enabling scaling.
Reservation Service is using a strong consistency to store reservations or spot assignment
Reservation added in the database can be captured using a Data capture tool like Debezium and add the reservation events to Kafka.
Availability Service will be used to easily search for available spots and
Payment Service will be used to enable the payment functionality using a payment provider chosen by the client
Ticket Service will
Request flows
- the client will do a POST request to do a reservation, the request will be guided to the Load balancer which will decide based on the Round Robin algo which server of reservation service to use. The reservation service will add the reservation or spot assignment into database and then will add a message to Kafka.
- Availability service will get the availability for a vehicle type and for a given period from now till today midnight. Will retrieve parking spot metadata from database and will get the blocks of availability from search index.
Detailed component design
- Kafka events: will be used to capture events of Reservation Service and payment Service being mapped to by the availability service to determine that one spot was reserved or freed up, also Kafka events service can be used by the notification service by registering to specific events
- Availability service can use a search index like Elastic Search to easily and performant search of spots for vehicle and availability.
- Notification service will subscribe to Kafka events to determine when a client should be notified
- Load balancer used to balance requests between instances of the same service using health endpoints to monitor the health of the instances/ containers
- Spots assignment: to prevent traffic in the parking spot we can assign blocks of cars size 10 to the first floor (in 10 minutes), then to second floor(10 minutes) depending where are free spots: assigning spots next to the entrance first but also improving the circulation in the rush hours when consecutive blocks of cars are assigned to next floors.
Trade offs/Tech choices
Availability service can use eventual consistency to display spot availability. Debezium tool to change data capture on the reservation can be used to publish events to Kafka, which can be used afterwards to calculate the availability of spots. The availability service will be out of sync with the current reservations since will take couple of seconds to receive through Kafka the new reservation or new events when the customer free up the parking spot.
Reservation service can use a strong consistency database to prevent overlapping reservation using a constraints to database or Serializable isolation level.
Kafka will enable high scalable distribution of events for Availability service to ingest and index the availability for certain spots
Sharding technique can be used to allow further grow of the database. The key used for sharding can be parking Spot Id overcoming the problem of a hot sharding.
Cache can be used to cache almost never changing data for a parking lot and parking spot.
The notification service can use Kafka to send notifications base on the users type of subscription to notification: mail (default), in app or SMS.
Failure scenarios/bottlenecks
-> Payment gateway service transient errors solved by retrying.
-> Consumer lag of the AvailabilityService Calculator which will process events of occupancy of a spot.
-> The user will be notified real time using of a spot being available in the application by using Server Side Events
-> Partition of the Kafka topic need to be changed.
Future improvements
Scaling of the notification service can be done by developing a microservice for each type of the notification that need to be delivered, using a topic in Kafka for each of it.