Rethinking 12306 Ticketing: A Domain‑Driven Design Model for Complex Train Reservations
This article analyses the unique business complexity of China's 12306 railway ticketing system, proposes a domain‑driven aggregate design centered on the train route, explains how to model seat availability and ticket issuance, and outlines a CQRS/event‑sourcing architecture to achieve strong consistency and high concurrency.
Preface
During the Spring Festival I came across an article stating that the business complexity of 12306 is far greater than that of typical e‑commerce sites such as Taobao. This observation motivated me to explore the core domain model of the 12306 system.
Another reason for writing this article is the suspicion that the current core domain model of 12306 is not well designed, which makes ticket‑purchasing logic extremely complicated, raises data‑consistency maintenance costs dramatically, and hinders high‑TPS ticket booking.
Requirement Overview
The core problem of 12306 is online ticket sales, involving two roles: users and the railway bureau. Users need to query seat availability and purchase tickets; the bureau needs to sell tickets. The system must support three core scenarios: query remaining tickets, purchase tickets, and the bureau’s ticket‑selling process.
Querying remaining tickets requires the user to provide departure station, destination station, and travel date, after which the system shows each train’s stations and seat‑type availability.
Purchasing tickets consists of reservation and payment; this article focuses on the reservation model.
Requirement Analysis
If a ticket is treated as a product, the problem looks similar to e‑commerce, but the number of possible tickets (SKUs) is huge because each pair of stations on a train creates a distinct ticket. For example, the G71 train with 17 stations and three seat classes yields 408 distinct tickets.
A ticket’s essential information includes departure time, departure station, destination station, train number, and seat number. For the system, a ticket is a credential that grants the holder a seat on a specific train segment.
Analyzing the train’s seat capacity shows that a seat can be sold for multiple non‑overlapping segments, allowing the number of sellable tickets to exceed the physical seat count. The key business rule is that, for every atomic segment (adjacent stations), the number of overlapping tickets plus one must not exceed the total seat count.
Model Design
Traditional E‑commerce Approach
Modeling each ticket segment as a separate product aggregate leads to an explosion of aggregates (e.g., 408 for G71) and requires updating many aggregates in a single transaction, causing high contention and potential deadlocks.
My Approach
Aggregate Design
The train (train‑route) should be the aggregate root responsible for ticket issuance. It stores the train number, seat count (by class), ordered list of stations, departure time, and the available quantity for each atomic segment. All ticket‑related decisions are made within this aggregate, ensuring strong consistency without database transactions.
How to Determine If a Ticket Can Be Issued
Given a reservation request, retrieve all atomic segments covered by the requested interval and attempt to decrement the available count for each segment. If all decrements succeed, the reservation succeeds; otherwise it fails.
Seat Allocation
The aggregate also maintains a pool of seats and the mapping between sold tickets and seats. When a reservation is possible, an algorithm selects a suitable seat, preferring reuse of already allocated seats to avoid mid‑journey seat changes.
Model Analysis Summary
Tickets are not core aggregates; they are the result of a reservation.
The train aggregate is the true core, handling availability checks, seat selection, atomic‑segment inventory updates, and storing sold tickets.
This design confines all state changes to a single aggregate, eliminating the need for distributed transactions while supporting high concurrency.
Architecture Design (Optional)
The system fits well with a CQRS architecture: the command side uses DDD and event sourcing (e.g., ENode) to process reservations, while the query side uses distributed caches for fast ticket‑availability queries.
Reservation Implementation
In‑memory + event sourcing allows each reservation to generate a single event, avoiding heavy database I/O and enabling rapid processing.
Ticket Query Implementation
Queries can be served from caches keyed by departure‑destination‑date or by atomic‑segment availability, ensuring near‑real‑time responses.
Conclusion
The article presents a domain‑driven model for 12306 that treats the train as the aggregate root, simplifies ticket issuance logic, and leverages CQRS and event sourcing to achieve strong consistency and high performance. Real‑world implementation would require close collaboration with domain experts.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
