System requirements


Functional:

  1. Supported vehicle types: 2 wheelers ( electric and ICE ), sedan size 4 wheel ( electric and ICE ). 6-8 wheeler bigger trucks ( ICE only )
  2. Multi-level parking. Each location can have different capacity and level based on proximity. e.g. Urban area and proximity to event location
  3. Same entry and exit for all types of vehicles.
  4. Cost estimation is done based on hours of parking.
  5. System shall be able to cater frequency of 1 million requests / second.
  6. Users can pre-book parking space upto 1 week before



Non-Functional:

  1. Uptime: 99.99 %
  2. Horizontally scalable
  3. User friendly
  4. Security: All users data shall be secure
  5. Response time: <100 ms
  6. Throughput: 10k req / sec




Capacity estimation

Assuming 1 out of 7 person owns a 4-Wheeler. 1/10th of these would use our service daily: 100 million people.

Data required to store single transaction ~ 100 B

Number of records inserted daily: 100 million * 100 B = 10 GB.

For 1 year = 3TB

Estimating for 10 Years = 30TB





API design

As all of these entries will be modifying db, these cannot be Get calls

  1. post /park?vn=<vehiclenumber>&type=2&elec=y
    1. return parking space where vehicle can be paraked
  2. post /unpark?vn=<vehiclenumber>
    1. Closes DB entry with after accepting payment
  3. post /book?vn=<vehiclenumber>&type=2&elec=y
    1. Reserves a slot for given type
  4. get /parkspace?type=<x>
    1. return parking space available for given type of vehicle






Database design

-- Table [ParkingTransactions] --

UniqueId ( uuid )

VehicleNumber ( 20 chars )

InTime ( dateTime )

OutTime ( dateTime )

ElectricConsumption ( number )

SlotAlotted (FK: string)

TransactionId ( FK )

ParkingBuildingId ( FK )


-- Table [ParkingSpace] --

MarkingNumber ( string )

BuildingDeatails

BuildingAdderss

MetaInfo (string)

State ( Enum )


-- Table [Transaction] --

UUID

Details


-- Table [PreBooking] --

CustomerId (FK)

RequestedStartTime ( DateTime )

Transaction ()


-- Table [Customer] --

CustomerId ( PK )

CustomerMetadata


High-level design

Table ParkingTransactions can be sharded based on ParkingBuildingId.

Services:

  1. CostCalculator
    1. Calculate cost based on space used and time parked
  2. Booking
    1. Prebooking and cancellation
  3. ParkingService
    1. finds required space based on
  4. SlotFinder
    1. Stores an active list of vacant slots
  5. PaymentService
  6. CustomerService
  7. AuthService






Request flows:



Detailed component design

Each component is horizontal scalable.

Every micro-service has its own database, and no sharing of DB is allowed.


  1. CostCalculator is a stateless service and hence do not need to access any DB.
  2. ParkingService is owner for below tables:
    1. ParkingTransactions
  3. SlotFinder service is owner for
    1. ParkingSpace


On Entering the building, vehicle is scanned to number plate and type. Post request is sent to "ParkService".

A distributed transaction is executed between SlotFinder and ParkService to block required slot and make a transaction entry.




Trade offs/Tech choices

Communication between microservice: gRPC

Communication between client and LB: REST

As we are not generating lot of data, SQL DB would be a fine choice.

Cache: Redis can be used.




Failure scenarios/bottlenecks

ParkService fails: Multiple instance will be running and pointing to same DB.

ParkService DB fails: A db replica is kept in sync in case of failover is required.


similar strategy for each service can be followed.


Natural calamity causing hardware failure: DataCenteres are kept in different geographical locations to avoid hardware failure in one continent


Any service fails to respond: exponential backoff while reissuing request.





Future improvements

What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?