How 12306 Handles Millions of Ticket Requests: High‑Concurrency Architecture Explained

This article analyzes the extreme traffic spikes of China's 12306 train ticket platform, detailing its distributed high‑concurrency architecture, load‑balancing strategies, inventory‑deduction techniques, and Go/Redis code examples that enable stable, oversell‑free ticket purchasing during peak holidays.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
How 12306 Handles Millions of Ticket Requests: High‑Concurrency Architecture Explained

Background

During holidays, millions of users in China try to purchase train tickets through the 12306 platform, creating a massive spike in QPS that can reach millions of requests per second.

1. Large‑scale high‑concurrency architecture

The system is deployed as a distributed cluster with multiple layers of load balancers and disaster‑recovery mechanisms (dual data centers, node fault tolerance, backup servers) to ensure high availability.

1.1 Load‑balancing overview

Three typical load‑balancing technologies are described:

OSPF – an interior gateway protocol that builds a link‑state database and can perform up to six‑path equal‑cost load balancing.

LVS – Linux Virtual Server, a cluster solution that distributes requests across servers and masks failures.

Nginx – a high‑performance HTTP reverse proxy that supports round‑robin, weighted round‑robin, and IP‑hash algorithms.

1.2 Nginx weighted round‑robin demo

# Configuration of load balancing
upstream load_rule {
    server 127.0.0.1:3001 weight=1;
    server 127.0.0.1:3002 weight=2;
    server 127.0.0.1:3003 weight=3;
    server 127.0.0.1:3004 weight=4;
}
...
server {
    listen 80;
    server_name load_balance.com www.load_balance.com;
    location / {
        proxy_pass http://load_rule;
    }
}

Local Go services for testing

package main
import ("net/http" "os" "strings")
func main() {
    http.HandleFunc("/buy/ticket", handleReq)
    http.ListenAndServe(":3001", nil)
}
func handleReq(w http.ResponseWriter, r *http.Request) {
    // write log, etc.
}

Using ab -n 1000 -c 100 http://www.load_balance.com/buy/ticket the four ports received 100, 200, 300, and 400 requests respectively, matching the configured weights.

2. Seckill system design choices

The ticket‑seckill process involves three stages: order creation, inventory deduction, and payment. Three strategies are compared:

Order‑first then inventory – simple but creates heavy DB write load under extreme concurrency.

Payment‑first then inventory – avoids underselling but can cause overselling and still incurs DB I/O.

Pre‑deduct inventory – reserves stock in memory, performs order creation asynchronously, and uses a timeout to release unsold tickets.

Orders are typically placed into a message queue (e.g., Kafka) for asynchronous processing.

3. The art of inventory deduction

Local in‑memory stock is combined with a centralized Redis store. Each machine holds a portion of the total tickets; when local stock is exhausted, the request falls back to Redis. A “buffer” stock on each node tolerates node failures.

Redis can handle up to 100 k QPS, and because most requests succeed locally, the number of remote Redis calls remains low.

4. Code demonstration (Go)

4.1 Initialization

type LocalSpike struct {
    LocalInStock     int64
    LocalSalesVolume int64
}

type RemoteSpikeKeys struct {
    SpikeOrderHashKey string
    TotalInventoryKey string
    QuantityOfOrderKey string
}

func NewPool() *redis.Pool { /* ... */ }

func init() {
    localSpike = LocalSpike{LocalInStock:150}
    remoteSpike = RemoteSpikeKeys{
        SpikeOrderHashKey:"ticket_hash_key",
        TotalInventoryKey:"ticket_total_nums",
        QuantityOfOrderKey:"ticket_sold_nums",
    }
    redisPool = NewPool()
    done = make(chan int,1)
    done <- 1
}

4.2 Local and remote deduction

func (spike *LocalSpike) LocalDeductionStock() bool {
    spike.LocalSalesVolume++
    return spike.LocalSalesVolume < spike.LocalInStock
}

const LuaScript = `        local ticket_key = KEYS[1]
        local ticket_total_key = ARGV[1]
        local ticket_sold_key = ARGV[2]
        local ticket_total_nums = tonumber(redis.call('HGET', ticket_key, ticket_total_key))
        local ticket_sold_nums = tonumber(redis.call('HGET', ticket_key, ticket_sold_key))
        if(ticket_total_nums >= ticket_sold_nums) then
            return redis.call('HINCRBY', ticket_key, ticket_sold_key, 1)
        end
        return 0`

func (r *RemoteSpikeKeys) RemoteDeductionStock(conn redis.Conn) bool {
    lua := redis.NewScript(1, LuaScript)
    result, err := redis.Int(lua.Do(conn, r.SpikeOrderHashKey, r.TotalInventoryKey, r.QuantityOfOrderKey))
    if err != nil { return false }
    return result != 0
}

4.3 HTTP handler

func handleReq(w http.ResponseWriter, r *http.Request) {
    redisConn := redisPool.Get()
    <-done
    if localSpike.LocalDeductionStock() && remoteSpike.RemoteDeductionStock(redisConn) {
        RespJson(w,1,"抢票成功",nil)
    } else {
        RespJson(w,-1,"已售罄",nil)
    }
    done <- 1
    writeLog(...)
}

4.4 Load testing

ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticket

The test shows the single‑node service handling over 4 000 requests per second with stable latency.

5. Summary

The article demonstrates a high‑concurrency ticket‑seckill system that avoids database I/O by performing most calculations in memory, uses Redis for centralized stock control, and employs load balancing and buffer stock to prevent overselling, underselling, and node failures.

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.

Backend Architectureload balancinghigh concurrencyticket seckill
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

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.