For users
For admin
Define what APIs are expected from the system...
1.Make a reservation
url: /user/parkinglot/booking
Parameters:
reqType: Post
returns: ReservationId, success or fail
2.Cancel a reservation
url: /user/parkinglot/cancel
Parameters:
reqType: Post
returns: success or fail, reason if failed
3.View the parking lot
url: /view/parkinglots
reqType: Get
returns: List of parking lots with the status of availability, type of the parking lot, occupancy percentage and estimated wait time
4.Entry the parking lot
url: /user/parkinglot/parking
reqType: Post
Parameters:
returns: parkingId, success or fail
5.Exit the parking lot
url: /user/parkinglot/exit
reqType: Post
Parameters:
returns: success or fail, reason if failed
6. Make the payment
url: /user/parkinglot/pay
reqType: Post
Parameters:
returns: success or fail, reason if failed
I would prefer relational database to store the data for the parking lot instead of non-relational database because of below reasons:
We have three load balancers for three service clusters: Parking service, Reservation service and Payment service, and they all connected to the shared Redis cache to speed up the read process and reduce the pressure of the database, and if any cache miss happens the service will make the request directly from the database.
Reservation flow
Client log in the system -> view the parking lots and select the available one -> request will be sent to the load balancer -> request distributed to one of the application service -> process the request and persist the data into database, and update the Redis cache -> return to the front-end
Parking flow
Client entry the parking lot -> identified by the system and request will be sent to the load balancer -> request distributed to one of the application service -> process the request and persist the data into database and update the Redis cache -> return to the front-end
Payment flow
Client log in the system -> check the reservation history -> select the latest one and make the payments -> request sent to load balancer and distributed to the application service -> service called the Wechat or the Alipay based on what user selected -> confirm the payments by the callback of the payment process and update the reservation to be paid/completed.
Pay for the additional fees (Or no reservations)
If user have parked more than the time he reserved or pay directly in the exit, the flow would be
Client scan the QR code -> request sent to load balancer and distributed to the application service -> service called the Wechat or the Alipay based on what user selected -> confirm the payments by the callback of the payment process and update the reservation to be paid/completed.
Pay for the additional fees (Or no reservations)
Table design for reservation:
UserId, reservationId, reservation start time, reservation end time, parkinglot type
Table design for parking service:
UserId, parkingId, start time, end time
Table design for the parking lot:
CarType, Disabilities (Y/N), isAvailable (Y/N)
1.Pessimistic locking/Optimistic locking - resolving the concurrency issue of the reservation service. Solution: Pessimistic locking need to be using the line-lock via the sql of select for update and it's managed by database itself, whereas Optimistic locking we should maintain a version in that row and check the version first, and take it to make the reservation, and only persist the data if version matches.
2.Relational or non-relational database - we select Relational database for this design
As I mentioned the volume of our system depends on the count of the lots, and generally won't be high. More importantly, we should guarantee the transaction security for the payments to not lose any money for our user, so Relational database is the best choice here.
1.When we make the payments for the current parking process, and we have sent the request to the external service(Wechat or Alipay), what should we do if we did not get any response?
For the overall transactions we have to ensure it's atomic,
2.The reservation service may encounter the concurrency issues when multiple people selected the same lot and make the requests, how to resolve it?
If A made the request for the reservation of lot a and B about to completed the reservation, A might not know this lot has been allocated by B, in this case our reservation service should use 'select...for update' to lock the row so no other transaction can modify it unit the current transaction is complete, so the lotId should be the contraint of that table.
We can build a analytic service to keep tracking the metrics of our service via promethius and Grafana, such as JVM metrics like memory usage and cpu usage, to visualize it in Grafana dashboard