From Monolith to Microservices: Lessons from Building a Train Ticket System

This article details how Mafengwo’s train ticket platform evolved from a simple LNMP monolith to a Java‑based microservice architecture, covering the technical decisions, infrastructure upgrades, service design, data modeling, state management, idempotency, and future roadmap for scaling and reliability.

Mafengwo Technology
Mafengwo Technology
Mafengwo Technology
From Monolith to Microservices: Lessons from Building a Train Ticket System

Introduction

Transportation is a core factor for users before travel. To help users complete the consumption decision loop, Mafengwo launched a large‑transportation business that allows purchasing train tickets, flight tickets, etc. This article shares technical experiences from the train ticket system across different development stages.

First Stage: From Nothing to Something

In this stage the goal was rapid business support. The train ticket business adopted a supplier‑purchase model and prioritized core functions such as querying seat availability, ticket purchase, payment, cancellation, and refund.

The initial architecture was LNMP (Linux, Nginx, MySQL, PHP). The system was divided into layers: access layer (App, H5, PC backend), Nginx as the entry layer, PHP application layer, middleware layer (MQ, ElasticSearch), and storage layer (MySQL, Redis). External dependencies included internal payment, order, and accounting systems as well as external supplier systems.

Problems of the monolithic architecture emerged over time: increased code modification cost, difficulty scaling the development team, low delivery efficiency, poor horizontal scalability, reliability issues, and hindered technical innovation.

Second Stage: Architecture Transition and Service Exploration

Starting in 2018 the large‑transportation business began shifting from LNMP to a service‑oriented architecture, moving the development language from PHP to Java and adopting the Java ecosystem.

Development Framework and Components

mlang – internal utility package

mes-client-starter – MES telemetry collection

dubbo-filter – Dubbo tracing

mratelimit – API rate limiting

deploy-starter – deployment traffic isolation

tul – unified login

cat-client – CAT monitoring wrapper

Infrastructure Stack

Kubernetes & Docker – agile infrastructure

Zabbix, Prometheus, Grafana – monitoring and alerting

ELK – log system

Gitlab + Jenkins + Docker + Kubernetes – CI/CD

Apollo – configuration center

Dubbo 2.x – microservice framework

RocketMQ – message center

Elastic‑Job – scheduled tasks

PinPoint, CAT – APM

The resulting DevOps‑plus‑microservice ecosystem is illustrated in the following diagram:

Service Design for the Ticket‑Snatching System

Design principles include isolation, autonomy, single responsibility, bounded context, asynchronous communication, and independent deployment. The system was split from both business and technical perspectives.

Business‑level services

Forward transaction service – order creation, payment, cancellation, ticket issuance, query, notification

Reverse transaction service – order reversal, refund, query, notification

Supplier service – request resources, create orders, cancel, seat reservation, ticket issuance

Activity service – daily activities, sharing, ranking statistics

Technical layers

Presentation layer – H5 and mini‑program, front‑end/back‑end separation

API layer – unified gateway exposing HTTP REST APIs

Service layer – business RPC services

Bridge layer – PHP‑Java proxy, Dubbo RPC for Java, HTTP gateway for PHP

Message layer – asynchronous processing (order status, seat reservation, payment)

Scheduled task layer – compensation and polling tasks

Data Model

The core data tables include order snapshot, ticket‑snatching order, segment, passenger, activity, item, fulfillment (ticket number), refund order, and refund item.

Order State Management

A finite‑state machine separates order status (init → order‑created → transaction‑success → closed) and payment status (init → pending → paid → closed). Events trigger transitions, and a set of seven close‑reasons (e.g., user cancel, payment timeout, operational close) are recorded to compute the external display status.

Idempotency Design

Idempotency ensures that repeated calls produce consistent results. For seat‑reservation messages, a unique serialNo is used to detect duplicates, and optimistic locking (CAS) is applied at the database level.

Third Stage: Service Promotion and System Capability Enhancement

After the ticket‑snatching system, the focus shifts to migrating the legacy electronic‑ticket system to a service‑oriented architecture, unifying the tech stack, and improving reliability, performance, and scalability.

The redesigned electronic‑ticket architecture adds new modules for supplier integration, forward/reverse transactions, search, and basic data services while retaining the previously built ticket‑snatching capabilities.

Search Optimization

To meet real‑time seat availability requirements, a multi‑channel caching strategy using Redis with a 10‑minute TTL and a 10‑second effective window is employed. Distributed locks prevent concurrent cache updates.

Message Consumption

RocketMQ handles asynchronous business messages such as order status changes, seat reservation notifications, and payments. It supports ordered consumption (single queue, single consumer), duplicate consumption handling (at‑least‑once semantics with idempotency), and transactional consumption (two‑phase commit).

Gray Release Strategy

A two‑phase gray rollout—first whitelist, then 20% traffic—is used to safely migrate traffic. Entry points are split between old and new systems, allowing gradual validation.

Future Plans

Refine service granularity (e.g., split transaction service into order query, creation, seat reservation, ticket issuance)

Isolate resources (DB, cache, MQ) per service

Support multi‑version gray releases for flexible testing

Conclusion

Technology must evolve alongside business needs, avoiding over‑design while addressing new challenges such as increased complexity, service governance, consistency, and performance.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSystem Architecturemicroservicestrain ticket
Mafengwo Technology
Written by

Mafengwo Technology

External communication platform of the Mafengwo Technology team, regularly sharing articles on advanced tech practices, tech exchange events, and recruitment.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.