Phase-wise Roadmap: Distributed Ticket Booking
System
This roadmap guides you through building a production-ready ticket booking microservices system in
iterative phases. Each phase focuses on core backend concepts (with Java 17, Spring Boot, Redis, MySQL/
PostgreSQL, Kafka, Docker) and delivers concrete outputs (code modules, diagrams, resume bullets, etc.).
Real-world problems (e.g. race conditions, failures, scaling) are introduced and solved, and key interview
concepts are highlighted and cited from industry sources.
Phase 1: Core Booking Service and Data Model (Monolith)
Feature: Implement the basic ticket booking functionality: create/view events, select seats, and book
tickets. Build RESTful CRUD APIs (e.g. POST /events , GET /events/{id} , POST /bookings ) using
Spring Boot and a relational database (MySQL/PostgreSQL). Secure the APIs minimally and handle errors
centrally (using @ControllerAdvice ).
Tech & Concepts: Spring Web (REST controllers), Spring Data JPA, Java 17, ACID transactions. Focus on data
modeling (Entities: Event, Seat, Booking, User) and transactional integrity. Each booking should be an
atomic database transaction to avoid double-booking. Use database constraints or locking to enforce
consistency.
Citations: A relational DB with transactions is essential to “ensure that only one user can book
a ticket at a time” and to handle high contention (e.g. using row-level locking or optimistic
concurrency) 1 .
Problems Tackled: Basic consistency and atomicity. Avoiding duplicate booking by leveraging DB
transactions. Designing normalized tables for events, seats, bookings.
Interview Concepts: ACID transactions, ORM (Hibernate/JPA), RESTful API design, exception handling,
logging, validation. Be ready to discuss data modeling and why a relational DB (MySQL/Postgres) is chosen
for transactional consistency.
Deliverables:
- Code: A Spring Boot service (e.g. BookingService , EventService ) with controllers, services,
repositories.
- Database Schema: ER diagram (tables for Users, Events, Seats, Bookings with keys/constraints).
- API Documentation: Swagger/OpenAPI spec or Postman collection for CRUD endpoints.
- Resume Bullet: “Designed and implemented core ticket booking REST APIs in Spring Boot with transactional
MySQL backend.”
Advice: Keep the initial codebase simple. Write integration tests (Spring Boot test with in-memory DB) to
verify booking transactions. Use JPA annotations for relations and add indexes on lookup fields (e.g. event
date). Document APIs and error formats. Practice explaining how a DB transaction prevents double-booking
(cite transaction isolation or @Transactional ).
1
Phase 2: Microservice Decomposition & Security
Feature: Refactor the monolith into separate microservices (e.g. User Service, Event Service, Booking
Service). Introduce an API Gateway (or Spring Cloud Gateway) as the entry point. Add authentication/
authorization using Spring Security (e.g. JWT tokens or OAuth2) so that only registered users can book
tickets.
Tech & Concepts: Spring Boot for multiple services (one per JAR), Spring Security (JWT/OAuth2),
independent databases (Database per Service pattern). Each service has its own schema and runs
independently. Communication between services is via REST calls or API Gateway routing.
Citations: Microservices architecture “structures an application as a collection of loosely
coupled, independently deployable services” – each service handles a business capability and
can be scaled or deployed without affecting others 2 .
Problems Tackled: Team isolation and scalability. Securing APIs so only authenticated users can book.
Avoiding single points of failure in the monolith.
Interview Concepts: Pros/cons of microservices vs monolith, service discovery/API gateway, stateless JWT
authentication, CORS, OAuth flows. Be prepared to explain how a gateway routes requests and enforces
security.
Deliverables:
- Code Modules: Separate Spring Boot projects (or modules) for Users, Events, Bookings, with shared
models if needed. Each service has its own DB (e.g. users_db , events_db , bookings_db ).
- Architecture Diagram: High-level deployment diagram showing services, API Gateway, and how they
interact.
- Resume Bullet: “Decomposed monolithic booking system into secure microservices (User, Event, Booking) with
Spring Boot and JWT authentication.”
Advice: Use Spring Security with JWT to make the system stateless. Store user credentials securely (bcrypt-
hashed). Configure cross-service REST clients (RestTemplate or Feign) with circuit breaker placeholders for
future use. Test auth flows (e.g. obtaining and using tokens). Include API keys or rate limiting early at the
gateway level.
Phase 3: Performance Optimization – Caching & Search
Feature: Improve read performance by caching frequently accessed data. For example, cache event and
seat information in Redis so that GET /events/{id} and seat availability checks are fast. Optionally
introduce a search index (e.g. Elasticsearch) or optimized queries for complex event searches (by date,
location).
Tech & Concepts: Spring Cache abstraction with Redis as the cache store, custom Redis clients, cache key
strategies and TTL. (Optionally, use Spring Data Elasticsearch for full-text search on event metadata.)
Citations: Using a Redis cache “improve[s] response times and reduce[s] load on the backend”
when handling spikes of concurrent users 3 .
2
Problems Tackled: Scaling read-heavy operations. Reducing database load and latency. Handling spikes
during popular events.
Interview Concepts: Caching strategies (cache-aside, read-through), cache invalidation, time-to-live (TTL),
cache eviction policies. Consistency issues (e.g. stale data) and when to refresh caches. Use of HTTP caching
headers (e.g. ETag) can also be mentioned.
Deliverables:
- Code: Annotate service methods (e.g. @Cacheable on event lookup) and configure a
RedisCacheManager in Spring Boot.
- Configuration: Properties for Redis (host/port), cache TTL settings.
- Performance Demo: Evidence (e.g. simple benchmark or log) showing cache hit vs miss.
- Resume Bullet: “Accelerated API responses by implementing Redis caching for event and seat data in Spring
Boot.”
Advice: Monitor cache performance (hit rates). Write tests to verify cache behavior (e.g. use embedded
Redis in tests). Handle cache misses gracefully. Plan how and when to evict/invalidate cache entries (e.g.
after a booking, evict affected seat data). Document caching layers clearly.
Phase 4: Concurrency Control & Idempotency
Feature: Make ticket booking safe under high concurrency and retries. Use distributed locking to prevent
two users from booking the same seat simultaneously, and enforce idempotency so that duplicate client
requests do not create multiple bookings.
Tech & Concepts: Redis-based distributed locks (e.g. using SETNX or Redisson) and idempotency keys
stored in Redis or a database. Use Spring AOP or a filter to handle an Idempotency-Key header (reject or
return cached response for duplicate requests).
Citations: In a distributed setup, “coordination between microservices is essential to ensure
consistency, avoid race conditions, and enforce mutual exclusion” 4 . A common approach is
Redis-based locking (using SETNX with TTL) to make seat-assignments atomic 5 .
Idempotency means “the data/system state will be the same no matter how many times the
API is successfully called with the same request” 6 , which we enforce by caching request
IDs.
Problems Tackled: Preventing double-booking and race conditions when many users select the same seat.
Handling retry or duplicate POST requests (e.g. due to network retries) without creating duplicate orders.
Interview Concepts: Distributed lock design (Redis Redlock, database locking), optimistic vs pessimistic
concurrency. Idempotent API design (idempotency keys). Race conditions and atomic operations.
Deliverables:
- Code: Implement locking around the critical section in BookingService (e.g. lock on seat ID before
decrementing availability). Add an idempotency filter or aspect that checks a unique request key before
proceeding.
- Tests: Concurrent booking test (multi-threaded) to ensure no double-booking. Test idempotent behavior
by replaying the same request.
3
- Resume Bullet: “Implemented Redis-backed distributed locks and idempotent endpoints to prevent race
conditions and duplicate bookings.”
Advice: Use Redisson or manually implement Redis lock with a safe TTL (avoid deadlock if a process
crashes). Carefully handle lock release in finally blocks. For idempotency, choose a storage (Redis or
DB) for request keys and set expiration. Write thorough integration tests (e.g. using Spring’s
@Transactional test with multiple threads) to simulate conflicts.
Phase 5: Fault Tolerance and Resilience
Feature: Add resilience patterns to handle partial failures. For example, wrap external calls (like payment
processing or calling other services) with circuit breakers and retries. Provide fallback responses or
degrade gracefully when downstream services are slow or unavailable.
Tech & Concepts: Resilience4j (CircuitBreaker, Retry, RateLimiter, Bulkhead) integrated with Spring Boot
( @CircuitBreaker annotations or functional decorators). Proper exception handling and timeouts in
REST clients ( RestTemplate or WebClient with timeout).
Citations: The circuit breaker “acts as a fail-safe mechanism to prevent repeated failures from
propagating in your system” 7 . Using Resilience4j (a lightweight Java library) you can
implement these patterns (Circuit Breaker, Retry, etc.) to improve stability 8 . This prevents
cascading failures and allows graceful fallback 9 .
Problems Tackled: Downstream services failing or timing out (e.g. payment gateway downtime), which
could cause threads to hang or retry indefinitely. Potential cascading failures where one slow service drags
down others.
Interview Concepts: Circuit breaker states (closed, open, half-open) 10 . Difference between fail-fast vs
retry strategies. Bulkhead isolation. Timeouts vs blocking. The importance of graceful degradation and
fallback logic.
Deliverables:
- Code: Annotate service methods (e.g. @CircuitBreaker(name="paymentService",
fallbackMethod="fallback") ) and configure thresholds in [Link] . Use Retry for
idempotent repeatable operations.
- Configuration: Resilience4j properties (failure rate thresholds, wait durations, etc.).
- Resume Bullet: “Built fault-tolerant Spring Boot services using Resilience4j circuit breakers and retries to
handle external failures.”
Advice: Simulate failures using mocks (e.g. make the payment service throw exceptions). Monitor circuit
breaker metrics (Resilience4j provides health indicators). Implement sensible fallbacks (e.g. cancel the
booking or queue it for retry). Add retries only for idempotent operations. Keep fallback handlers simple.
Phase 6: Asynchronous Processing with Kafka
Feature: Refactor synchronous processes (like booking creation and confirmation) into an event-driven
architecture using Kafka. For example, when a booking is created, publish a BookingCreated event.
Another service (or a consumer thread) processes payment and then emits a PaymentCompleted event,
4
which the booking service listens to finalize the booking.
Tech & Concepts: Apache Kafka as the message broker; Spring for Apache Kafka (using KafkaTemplate ,
@KafkaListener ). Topics for key events (e.g. bookings , payments ). Decoupling through pub/sub and
using consumer groups for scalability.
Citations: Kafka enables asynchronous communication: services communicate via events
instead of blocking HTTP calls, which “decouples services and enhances scalability” 11 . Kafka
is designed for high throughput and durability (e.g. handling millions of messages per
second with replication) 12 , making it ideal for event-driven microservices.
Problems Tackled: Removing tight coupling of services and improving scalability. Ensuring the booking
workflow can proceed even if parts are slow (e.g. payment processing can happen in the background).
Handling spikes by buffering in Kafka.
Interview Concepts: Event-driven architecture, message ordering (Kafka partitions), at-least-once vs
exactly-once semantics, consumer groups. Differences between synchronous (REST) and asynchronous
processing.
Deliverables:
- Code: Spring Boot producers (on booking create) and consumers (for payment results). Define event
schemas (POJOs).
- Diagram: Sequence diagram showing the booking/payment event flow through Kafka.
- Resume Bullet: “Refactored the booking workflow to an event-driven architecture using Spring Kafka for
asynchronous, scalable communication.”
Advice: Use schemas (JSON or Avro) for event payloads. Make consumers idempotent (in case of message
re-delivery). Test with an embedded Kafka or a local cluster. Handle deserialization errors gracefully. Ensure
that producing to Kafka is also done within a transaction or an outbox pattern to avoid lost events.
Phase 7: Distributed Transactions & Saga Pattern
Feature: Implement distributed transaction management for the multi-step booking process. For
instance, coordinate booking creation and payment so that they either both succeed or any partial state is
rolled back (compensated). Use the Saga pattern instead of traditional 2PC (two-phase commit). This could
be either a choreography-based saga (each service emits/consumes events) or an orchestration-based
saga (a central orchestrator service triggers steps).
Tech & Concepts: Saga pattern with Kafka events. Compensating transactions (e.g. issue a refund or
release a seat if payment fails). (Optionally, use an orchestrator microservice or a state machine.) Consider
the Outbox pattern for atomic DB-and-event commits.
Citations: A Saga is “a sequence of local transactions” across services; each transaction
publishes an event to trigger the next. If a step fails, the saga executes compensating
transactions to undo previous changes 13 . Kafka’s durability guarantees (“messages are not
lost even in case of failures”) make it well-suited for implementing sagas 14 .
Problems Tackled: Maintaining data consistency across services (e.g. BookingService and
PaymentService). Avoiding partial state (e.g. seat held without payment). Ensuring eventual consistency via
5
compensating actions rather than a single ACID transaction.
Interview Concepts: Saga vs 2PC (no global lock, high availability). Orchestration vs choreography
approaches. Compensating transaction design. Outbox pattern to reliably publish events. Trade-offs (lack of
isolation in sagas 15 ).
Deliverables:
- Code: Saga handlers or an orchestrator flow that listens for events and triggers compensations on failure.
For example, on payment timeout issue a BookingCancelled event.
- Diagrams: Flow diagram of the saga (e.g. booking -> payment -> confirmation or rollback).
- Resume Bullet: “Designed a saga-based workflow for distributed transactions, ensuring data consistency
across Booking and Payment services.”
Advice: Clearly document the saga flow and compensation steps. Write integration tests for success and
failure paths. Use durable message streams (Kafka) to avoid lost events. Keep each local transaction
idempotent. Review sagas vs alternative patterns (like 2PC, which is usually avoided in microservices) 13 .
Phase 8: Rate Limiting, Observability, and Deployment
Feature: Harden the system with operational concerns. Implement rate limiting (e.g. allow only N booking
attempts per IP or user per minute) using Redis or Resilience4j RateLimiter. Add observability: structured
logging, metrics (Prometheus/Grafana), and distributed tracing (Zipkin/OpenTelemetry). Finally,
containerize services with Docker and prepare for cloud deployment.
Tech & Concepts: Redis counters or token-bucket for rate limiting; Resilience4j RateLimiter. Micrometer
metrics, Spring Boot Actuator, Zipkin for tracing. Docker (Dockerfiles, Compose/Kubernetes manifests). CI/
CD pipelines for building images.
Citations: Redis is ideal for rate limiting because of its speed and built-in TTL/atomic counters:
“Redis provides optimized data structures… and with its built-in TTL it allows for efficient
management of memory” 16 , enabling simple fixed-window or sliding-window rate limiting.
Problems Tackled: Preventing abuse (e.g. bots) and protecting downstream services from overload.
Gaining insight into system health (request rates, error rates, latencies). Ensuring consistent deployment
across environments.
Interview Concepts: Algorithms for rate limiting (fixed window, sliding window, token bucket). Circuit
breaker vs rate limiter. Importance of logging/tracing in microservices. Containerization benefits
(immutable deploys).
Deliverables:
- Rate Limiting: Code/configuration (e.g. Spring interceptor or gateway filter) that enforces limits, backed
by Redis.
- Monitoring: Dashboard screenshots or metrics samples (e.g. number of bookings per minute, error
rates). Logging format example.
- Containerization: Dockerfiles for each service, and a [Link] or Kubernetes YAML for
local testing.
- Resume Bullet: “Implemented Redis-backed rate limiting and containerized services for production-ready
deployment.”
6
Advice: Test rate limiting under simulated load. Use environment variables for configurable limits. Expose
health endpoints ( /actuator/health ) and secure them. Perform end-to-end tests in Docker Compose.
Document your CI/CD steps (e.g. GitHub Actions or Jenkins).
Each phase builds on the last, introducing new concepts and complexity. By the end, you will have a
comprehensive ticket booking system showcasing modern backend skills: microservices architecture,
Spring Boot APIs, Redis usage (locking, caching, rate limiting), event-driven design with Kafka and sagas,
fault tolerance with Resilience4j, and deployment with Docker. This progressive project, with detailed
diagrams and code, can form a strong GitHub portfolio and provide rich talking points for system-design
interviews (e.g. explaining Saga vs 2PC, circuit breakers, distributed locking) – all grounded in the above
cited industry patterns 13 8 .
Sources: Concepts and patterns above are supported by system design literature and tutorials 5 1 6
4 16 11 13 2 8 .
1 Design a Ticket Booking Site Like Ticketmaster | Hello Interview System Design in a Hurry
[Link]
2 Kafka and Microservices: Implementing an Event-Driven Microservices Architecture | by Ganesh
12
Nemade | Medium
[Link]
e3c5bba0513f
3 5 Designing Scalable Booking System with Microservice architecture | by Abhirbkulkarni | Medium
[Link]
4 Handling Distributed Locks in Microservices Using Redis with Spring Boot | by Rahul Kumar | Medium
[Link]
6 Spring Boot 3: build the efficient Idempotent API by Redis | by Noah Hsu | Level Up Coding
[Link]
7 8 9 10 Spring Boot - Circuit Breaker Pattern with Resilience4J - GeeksforGeeks
[Link]
11 Kafka with SAGA Design Pattern. Each HTTP request occurs network… | by Dushan Senadheera |
14
Medium
[Link]
13 15 Pattern: Saga
[Link]
16 Rate Limiting in Spring with Redis
[Link]