My Solution for Design an Efficient Parking Lot System with Score: 8/10
by pulse_monolith663
System requirements
Functional:
- The parking lot should have multiple floors where users can park their cars.
- The parking lot should have multiple entrances and exit points.
- The system should not allow more vehicles than the maximum capacity of the parking lot. If the parking lot is full, a message should show at the entrance panel to alert users who want to park in.
- Each floor will have many parking spots.
- Parking spot should have various types such as Compact, Large, Handicapped, Motorcycle, etc.
- Each parking floor should have some specific spots for electric car, and users can pay and charge their car using a electric panel.
- Each floor should have a display board to show any free parking spot for each spot type.
- Users can collect a parking ticket from any entrance and can pay the fee at any exit point.
- There is an automated exit panel which can accept users payment, if they do not want to pay at the exit point.
- Users can pay by either cash or credit card.
Non-Functional:
- Scalability: the system should support a large enough number of parking lots.
- Security: all data should be safely storage
- Consistency: The data should be handled properly, for example, no double-parking, no wrong alert to tell users the parking lot is full but there are still some vacant spots.
Capacity estimation
I assume:
- The company has operations in 10 countries.
- The company has 100 parking lots, on average, in one country.
- On average, each parking lot has a capacity of 200 cars.
- On average, each user park their car with 4 hours.
Estimate:
Everyday will generate (24/4) * 200 * 100 * 10 = 1200000 tickets and receipts.
- Each ticket would mainly consists of:
- ticket_id (20 bytes)
- parking_lot_id (20 bytes)
- start time (8 byte)
- end time (8 byte)
- receipt_id (20 bytes)
- status (1 byte)
- Roughly totaling 80 bytes.
so each day will produce 96MB data, every year will product 34GB data.
API design
vehicle_enter(parking_lot_id, vehicle_type); return a number that can be a ticket_id
vehicle_exit(parking_lot_id, receipt_id, vehicle_type);
check whether the receipt has been paid or not: if not paid, return false, otherwise, return true.
pay(parking_lot_id, ticket_id): return a receipt number.
show_capacity(parking_lot_id): return the current capacity.
Database design
parking_lot:
parking_lot_id,
lot_capacity_id,
status
lot_capacity:
lot_capacity_id,
spot_type (Compact, Large, Handicapped, Motorcycle, etc. ),
spot_capacity,
spot_used_number
user_record:
ticket_id,
parking_lot_id,
start_time,
end_time,
receipt_id,
status (using, leave)
transaction:
receipt_id,
ticket_id,
payment_method,
payment_time,
status(paid, confirmed)
High-level design
- CDN can boost the request of some static resources.
- Load Balancer can direct request to multiple servers to uniform the request flow.
- parking service handle vehicle enter and exit, and also accept pay action from users.
- payment service will receive request from MQ to handle the payment, after that it will store the payment information to database. Moreover, payment status will be send back to parking service and forward to notification service.
- notification service will notify the users with the payment result.
Request flows
- Client will firstly check the capacity at the entrance panel, return by the parking service.
- Client will enter the parking lot, vehicle_enter() will be invoked, client will received a ticket with a ticket_id.
- Before exit, client needs to pay the parking fee, invoke the pay(), then will return a payment result.
- Finally, client will leave the parking lot, invoke the vehicle_exit(). vehicle_exit() will take the ticket_id as input, to check whether the client has been paid for the ticket or not.
Detailed component design
Payment service might have a high possibility of shutdown, so it may need to design concisely when users are paying for fee. When the user has submit the payment request to the parking service, parking_service will not only just send a request to MQ, but also generate a receipt number to the user, which will be also stored into the transaction table. During the downtime of payment service, when users can exit the parking lot, parking_service will check the receipt_id exists or not, if the receipt exists, the user will be allow to leave. After the payment service back online, it will return the payment status to the parking_service and parking_service will update the receipt that are in paid status to confirmed status. This approach actually implements a local payment record to keep track of the user parking status.
Trade offs/Tech choices
The biggest decision point was the database. For this service, I chose Relational Database over NoSQL Database. Because RDB provides strong consistency, which is beneficial for a payment service. Users can not leave util they pay for their parking fee, which is need to be 100% sure in this situation.
NoSQL database, for example MongoDB, would provide a better horizontal scalability than RDB. But for this service, I decided the benefit of RDB outweighs that of NoSQL DB.
Failure scenarios/bottlenecks
- I think when a super show ends, a large number of uses will pay for their fee, at the same time the MQ and the payment service will be very stressful. To mitigate this problem, payment service should be planning to scale up to a certain capacity to consume all the request received from the MQ. MQ should also be prepared to scale up, to prevent a large number of message arrival.
- This system relies on the ticket very much. It is possible If the users lost their ticket. To handle this situation, we need to establish a policy for lost tickets that includes potential fees or penalties. Users might be charged a flat rate or be required to pay the maximum daily fee if they cannot present a ticket.
Future improvements
- A spot reservation feature should be considered.
- parking allocation is also useful for users, in order to save the time looking for available parking spot.