How to Build a High‑Concurrency Ticket‑Spike System Like 12306
This article explores the challenges of massive ticket‑buying spikes during holidays, explains the multi‑layer load‑balancing architecture, presents Go and Nginx configurations for weighted routing, demonstrates Redis‑based pre‑deduction of stock with Lua scripts, and shares stress‑test results showing thousands of requests per second on a single node.
Large‑Scale High‑Concurrency System Architecture
During holidays, millions of users compete for train tickets on 12306, creating extreme QPS. The author studied the backend architecture and built a simulation for handling 1 million concurrent users buying 10 000 tickets.
Load Balancing Overview
Three‑layer load balancing (OSPF, LVS, Nginx) distributes traffic across a distributed cluster.
OSPF (Open Shortest Path First) builds a link‑state database and can perform load balancing across up to six equal‑cost paths.
LVS (Linux Virtual Server) provides IP‑level load balancing, automatically masking server failures and presenting a high‑availability virtual server.
Nginx implements weighted round‑robin, IP‑hash, and other algorithms; the example focuses on weighted round‑robin.
Nginx Weighted Round‑Robin Demo
# Configure 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;
}
}Go Service Example
package main
import (
"net/http"
"os"
"strings"
)
func main() {
http.HandleFunc("/buy/ticket", handleReq)
http.ListenAndServe(":3001", nil)
}
// handle request and write log
func handleReq(w http.ResponseWriter, r *http.Request) {
failedMsg := "handle in port:"
writeLog(failedMsg, "./stat.log")
}
func writeLog(msg string, logPath string) {
fd, _ := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
defer fd.Close()
content := strings.Join([]string{msg, "
"}, "")
fd.Write([]byte(content))
}Stress Test
Using ApacheBench (ab) with 10 000 requests and 100 concurrent connections, the single‑node service handled over 4 000 requests per second.
ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticketStock Deduction Strategies
The article compares three approaches: order‑first‑then‑deduct, pay‑first‑then‑deduct, and pre‑deduction with Redis. Pre‑deduction stores a portion of inventory locally, reduces it in memory, and asynchronously updates a global Redis hash to guarantee atomicity and avoid DB I/O.
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 (RemoteSpikeKeys *RemoteSpikeKeys) RemoteDeductionStock(conn redis.Conn) bool {
lua := redis.NewScript(1, LuaScript)
result, err := redis.Int(lua.Do(conn, RemoteSpikeKeys.SpikeOrderHashKey, RemoteSpikeKeys.TotalInventoryKey, RemoteSpikeKeys.QuantityOfOrderKey))
if err != nil { return false }
return result != 0
}Conclusion
Key takeaways:
Load balancing splits traffic, allowing each node to operate at peak efficiency.
Go’s native concurrency and channel‑based locking provide safe, high‑throughput request handling.
In‑memory stock handling combined with Redis atomic operations eliminates costly DB I/O while preventing oversell and undersell.
Buffer stock on each node tolerates server failures, ensuring overall availability.
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.
