Detailed Component Design
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
API Gateway
- Description: Handles incoming requests, and retrieves data from caching service for popular queries, or routes to Service Layer
Caching Service
- Description: Responsible for storing popular queries
- Caching maintenance mechanisms
- The underlying storing system should utilize Time-To-Live expiration strategy and cache purging to remove stale data
- Eviction policy: Can be Least Recently used or Least Frequently used
- We need to ensure strong consistency on reservation data. When user checks the availability for a parking lot, the system can quickly check the cache for availability, but the final reservation must be committed to the data to ensure that no two users can reserve the same spot simultaneously.
Load Balancer
- Description: Route requests to different instances of services based on different conditions like geographical nearest, numbers of instances spawned, etc.
Parking Lot Lookup Service
- Description: Handles parking lot search/lookup/recommendations.
- Consistency vs. Availability
- When calculating available spots for a parking lot, the service needs to check both reservation table and parking lot table. This query might take a long time, so in order to enhance user experience when looking up a spot, we could utilize the caching service to handle popular queries. When making the final reservation, we need to ensure consistency to prevent double-booking, which means the request needs to go through reservation service and retrieve data from the database.
Reservation Service
- Description: Handles reservation creation/lookup/cancel. Talks to Payment Service to get payment/refund information and to Data System to update reservation data.
- Non-Functional Requirements
- Scalability: Can scale horizontally by adding more instances, or vertically by upgrading existing instances
- Performance: during traffic burst, There are two payment verification approaches
- synchronous: makeReservation API calls Reservation Service to store reservations to Reservation Table with 10 minutes TTL. If user initiates payment within 10 minutes, Reservation Service will delegate the request to Payment Service and waits for a response. If payment is successful, the data entry will be flipped to a longer TTL (can be longer than reservation end time for history lookup), and Reservation Service will send back reservationId and confirmationId to user.
- asynchronous: To handle traffic burst, we can implement a non-blocking system to make reservations. When user initiates the reservation and gives payment details, we can send the request to a queue. Requests in the queue will be processed by Reservation Service one by on. Reservation Service needs to first check if the spot is still available from the Database. Reservation Service then talks to Payment Service for payment, one by one. If successful, we can utilize webhook mechanism to notify users on web or app, or send out an email notification. If two users try to reserve the same spot, we will abort the second request, and notify the user of the failure.
- Here I recommend asynchronous to avoid conflicting transactions to be processed at the same time
- Reliability: Redundant instances behind a load balancer
- Consistency: Read operations are consistent. If there is a double-booking during write operation, where Data System returns a collision error, we need to notify users of the reservation failure.
Payment Service
- Description: Handles payments and refunds. Send back to Reservation Service payment/refund status.
Gate Service
- Description: Handles check-ins/outs. Talks to Payment Service to get late fee information and to Data System to update reservation data for late fee.
Late Fee Service
- Description: Handles late fee payment. Send back late fee payment status to Gate Service.
Database
- Description: Stores Reservation data, parking lot data, and analytics data
- Data modeling
- Reservation table: stores reservation information
- Columns: reservationId, confirmationId, userId, parkingLotId, timeRange, plateNumber, vehicleSize, paymentId, paymentStatus, lateFeeId, lateFeeStatus, needAccessibility
- Indexing: reservationId
- Sharding: parkingLotId, startTime
- Parking Lot Table: stores parking lot information
- Columns: parkingLotId, priceRate, operatingHours, location, number of spots of different kinds, etc
- Indexing: parkingLotId
- Analytic data
- User metrics
- Popular parking lots
- User actions (make/cancel reservations, early/late check-outs)
- Performance metrics
- Response time
- Error rates
- A/B testing data
- Non-functional requirements
- Scalability: Implement database sharding to distribute data across different instances
- Performance: Recommend using relational database to store data, since queries are complicated
- Reliability: Database replicas can help recover when one instance is down
- Consistency: Read operations can be concurrent. Write operations can be concurrent among different database shards.