How WeChat Resets 1 Billion Step Counts at Midnight Without Crashing
WeChat avoids server crashes during midnight step-count resets for 1 billion users by using logical time-based versioning instead of physical updates, a custom PaxosStore for atomic increments, delayed double-write buffers for clock skew, Redis ZSet sharding for rankings, and asynchronous cold-data archival during low-traffic hours.
Why a Naive MySQL UPDATE Fails
At midnight, nearly 1 billion active WeChat users simultaneously reset their step counts, trigger yesterday's settlement, fetch group leaderboards, and generate billions of "like" write conflicts. This is a coordinated, clock-driven DDoS with no user-behavior buffer.
A typical reflex is a cron job running UPDATE on a 1-billion-row table. That would cause massive row/table lock contention, saturate IOPS, and deadlock the database.
WeChat's Storage Layering
MySQL as Final Immutable Archive
WeChat retains MySQL but places it at the end of the storage chain. All burst traffic (likes, high-frequency step uploads, leaderboard reads) is absorbed 100% in the memory cache layer and custom distributed middleware. Only aggregated, peak-shaved, cleaned "cold ledgers" reach MySQL via message queues.
Aggressive Sharding by UIN
WeChat runs hundreds of thousands of MySQL instances. Users are hashed by UIN into tiny shards — each table handles ~10,000 users. At midnight, the global peak is spread across countless physical servers; a single instance only sees its 10,000 users writing one history record each.
Core Storage: PaxosStore
WeChat's core businesses (Moments, third-party login, WeChat Run) run on PaxosStore , a home-grown, multi-replica, strongly consistent distributed KV/Table store based on the Paxos protocol.
Peak absorption: PaxosStore uses memory + WAL (write-ahead log). Step uploads perform atomic increments in memory and persist logs, delivering throughput orders of magnitude higher than traditional RDBMS.
UIN routing: Step data is numeric. PaxosStore keys on UIN (uint32_t) for O(1) reads/writes, forming an unshakeable "flood wall" at the front end.
Multi-DC Autonomous Loops
WeChat adopts "user-affinity autonomy": writes go to the user's home data center (e.g., Shenzhen for southern users, Shanghai for northern). Leaderboard settlement runs locally in each DC's cache cluster, then asynchronously replicates across Tencent's backbone, eliminating cross-region latency stalls.
Algorithm: Logical Zeroing via Time-Based Versioning
True high-concurrency systems never perform physical deletes or synchronous updates on the hot path. WeChat's "instant zeroing" secret: data is never actually cleared; only the time pointer changes.
Storage Key Design
Keys embed the date: User:Steps:20260515:UIN_12345 → 12,800 steps; User:Steps:20260516:UIN_12345 → 15,400 steps; User:Steps:20260517:UIN_12345 → 0 (uninitialized).
Zero-Point Switch
When the clock ticks from 23:59:59 to 00:00:00, the business layer's date string flips from 20260516 to 20260517. The first post-midnight upload or page view reads/writes the new day's key, which defaults to 0 because it hasn't been initialized. WeChat never iterates 1 billion users to set zeros; it simply moves the write target from "yesterday's plate" to "today's plate" — an O(1) logical reset.
Handling Clock Skew: Delayed Double-Write Window
NTP cannot guarantee perfect alignment across servers and 1 billion phones. Some clients may lag seconds behind, still uploading yesterday's steps after midnight.
To avoid data loss or misattribution, WeChat uses a 5-minute dual-write window (e.g., 23:58–00:03) : incoming step streams increment both yesterday's and today's keys. This guarantees yesterday's champion data stays accurate while today's ledger starts smoothly. After the buffer, yesterday's key becomes read-only cold data awaiting async archival. This is a classic "space-for-time-consistency" trade-off.
Leaderboards: Avoiding Redis BigKeys
Friend Rankings: Lazy Load on Social Graph
There is no global leaderboard. On first open after midnight, the app fetches the user's ~200 friend UINs, does a bulk MGET from memory cache for today's steps, sorts locally in application memory, and renders. This turns an O(N) global write amplification into O(k) read fan-out, naturally staggered by users' own refresh times.
Group Rankings: Hash Sharding by Group_ID
Each group owns a tiny ZSet. WeChat hashes Group_ID across thousands of Redis nodes: Hash(Group_ID) % Redis_Nodes. Even if millions post in groups at midnight, load is physically isolated per node, keeping every server in safe territory.
Cold Data Archival in the Nightly Trough
Past-day keys lingering in expensive memory (Redis/PaxosStore) would explode costs. During the 02:00–04:00 low-traffic window, a distributed scheduler (Flink/batch) quietly:
Async batch archival: Low-priority, throttled threads flush yesterday's frozen data to the persistent sharded database (or HBase).
TTL expiry: Old keys carry a 2–3 day TTL; once safely on disk, memory entries auto-evict.
This hot/cold separation — memory for live concurrency, disk for history — delivers both midnight silkiness and cost control.
Interview Answer Template
When asked to design a 1-billion-user midnight reset system, structure the answer in four steps:
Storage selection: Reject monolithic MySQL; use it only as decoupled archival ledger with strict UIN sharding (e.g., 1024 databases × 1024 tables). Front-end: memory+WAL strong-consistent KV (like PaxosStore) for atomic increments.
Logical zeroing: Zero physical writes at midnight. Key = User:Steps:{Date}:{UIN}. Date pointer flip routes traffic to new key, defaulting to 0. Turns 1 billion clears into O(1) pointer shift.
Clock-skew buffer: 5-minute dual-write window (23:58–00:03) writing to both old and new keys, ensuring accuracy and smooth handover.
Leaderboard & archival: Friend rankings via lazy-loaded friend-graph MGET + in-app sort; group rankings via Group_ID hash sharding. Nightly 02:00–04:00 async flush to persistent store with TTL cleanup.
Technical Essence
The core philosophy: avoid the brute force, leverage structure. Top architects don't optimize physical delete speed; they change the data structure (time-versioned keys) to dissolve a disaster-scale scenario into nothing. Demonstrating "space-for-time", "logical over physical deletion", and "sharding for isolation" mindset signals senior/architect-level system thinking.
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.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
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.
