Designing a High‑Concurrency Ticket‑Spiking System for 1M Users and 10K Tickets

This article explains how to architect a high‑concurrency ticket‑seckill system that can handle one million simultaneous users buying ten thousand tickets, covering load‑balancing strategies, Nginx weighted round‑robin configuration, Go service implementation, Redis‑based inventory management, and performance testing results.

dbaplus Community
dbaplus Community
dbaplus Community
Designing a High‑Concurrency Ticket‑Spiking System for 1M Users and 10K Tickets

1. Large‑Scale High‑Concurrency System Architecture

High‑concurrency systems are typically deployed as distributed clusters with multiple layers of load balancing and disaster‑recovery mechanisms such as active‑active data centers, node fault tolerance, and server backup to guarantee high availability. The diagram below illustrates a simple architecture.

2. Load‑Balancing Overview

Three layers of load balancing are introduced:

OSPF (Open Shortest Path First) – an interior gateway protocol that can perform up to six equal‑cost paths for load distribution.

LVS (Linux Virtual Server) – a cluster technology that distributes requests across a pool of servers while masking server failures.

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

3. Nginx Weighted Round‑Robin Demo

Weighted round‑robin is configured via the upstream block. The example assigns weights 1‑4 to four backend services listening on ports 3001‑3004.

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;
    }
}

The local /etc/hosts file is edited to map www.load_balance.com to the loopback address, and four Go HTTP services are started, each listening on one of the ports.

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) {
    // implementation omitted for brevity
}

Using ab to stress‑test shows request distribution of 100, 200, 300, and 400 respectively, matching the configured weights.

4. Seckill System Design Choices

The article discusses three typical order‑processing flows for a ticket‑seckill system:

Create order then deduct inventory – simple but incurs heavy DB I/O and can be vulnerable to malicious orders.

Deduct inventory after payment – avoids underselling but may cause overselling under extreme concurrency.

Pre‑deduct inventory and create the order asynchronously – stores inventory in memory, reduces DB I/O, and uses a timeout to reclaim unsold tickets.

The third approach is chosen because it minimizes database operations and improves response speed.

5. Inventory Deduction Strategies

Each server keeps a local in‑memory stock counter; a Redis hash stores the global total stock and the number of tickets sold. The local deduction function increments a sales counter and checks it against the local limit.

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

The remote deduction uses a Lua script to atomically read and update the Redis hash.

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
`

Before starting the service, the Redis hash is initialized:

hmset ticket_hash_key "ticket_total_nums" 10000 "ticket_sold_nums" 0

6. Request Handling Logic

The HTTP handler obtains a Redis connection, attempts local deduction and remote deduction, and returns JSON indicating success or “sold out”. The result is also written to ./stat.log for later analysis.

func handleReq(w http.ResponseWriter, r *http.Request) {
    redisConn := redisPool.Get()
    LogMsg := ""
    if localSpike.LocalDeductionStock() && remoteSpike.RemoteDeductionStock(redisConn) {
        util.RespJson(w, 1, "抢票成功", nil)
        LogMsg = "result:1,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
    } else {
        util.RespJson(w, -1, "已售罄", nil)
        LogMsg = "result:0,localSales:" + strconv.FormatInt(localSpike.LocalSalesVolume, 10)
    }
    writeLog(LogMsg, "./stat.log")
}

7. Performance Test

Running ab -n 10000 -c 100 http://127.0.0.1:3005/buy/ticket on a low‑end Mac yields about 4,300 requests per second, average latency ~23 ms, and zero failed requests. Log analysis confirms that traffic is evenly distributed and Redis remains stable.

8. Conclusions

The prototype demonstrates that a high‑concurrency ticket‑spiking service can be built without frequent database writes by combining weighted Nginx load balancing, per‑node in‑memory stock, and a Redis‑backed global stock counter. The design also tolerates a few node failures through a buffered “extra stock” mechanism, ensuring no overselling or underselling.

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.

Distributed Systemsload balancingRedisGohigh concurrencyNGINXticketing system
dbaplus Community
Written by

dbaplus Community

Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.

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.