Design, Migration, and High‑Performance Architecture of Vivo Mall Coupon System
Vivo Mall transformed its monolithic coupon component into an independent, sharded microservice through a rolling, dual‑write migration, employing Redis distributed locks, batch inserts, multi‑level caching, and read‑write splitting to eliminate bottlenecks, achieve non‑downtime deployment, and deliver scalable, high‑performance coupon handling for future growth.
Vivo Mall’s coupon system is a core component of its e‑commerce marketing platform. Originally embedded in the monolithic mall application, the coupon functionality was split into an independent service in 2019 to address scalability, coupling, and iteration constraints.
Business background
Coupons serve as flexible marketing tools for promotions, user acquisition, and various business scenarios such as device trade‑in, in‑app benefits, and partnerships with external advertisers. The system supports four key processes: creation (rules and thresholds), distribution (multiple issuance methods), usage (purchase and refund handling), and statistics (issuance, redemption, and product data).
System evolution
Early integration caused storage bottlenecks, high coupling with the mall, and limited iteration speed. To solve these issues, the coupon service was decoupled and re‑architected as an independent microservice, with both stop‑the‑world and rolling migration strategies. Vivo chose the rolling (non‑downtime) migration, which involved:
Stopping backend coupon operations before migration.
Switching the database write mode to single‑write (old mall DB) for static data migration.
Enabling dual‑write to both old and new databases while validating data.
Migrating dynamic user‑related data.
Switching the data source to the new coupon DB and finally disabling dual‑write.
After migration, the request topology routes traffic to the new coupon service.
System design
3.1 Sharding strategy
To overcome single‑table limits, user coupons are sharded by user ID. The routing formula is:
databaseSuffix = hash(userId) / M % N tableSuffix = hash(userId) % MThus, each user’s coupons reside in the same database and table, facilitating aggregation and query efficiency.
3.2 Coupon issuance methods
Unified claim interface
Backend targeted issuance
Code‑based redemption
3.2.1 Unified claim interface
Ensures accurate validation of inventory and per‑user limits under high concurrency. A distributed lock based on Redis is acquired before checking the claim count, preventing duplicate claims.
Stock deduction can follow two approaches:
Option 1: Direct database update (simple, transactional, but suffers from row‑lock contention under heavy load). Option 2: Redis‑based decrement using INCRBY (fast, but requires handling cache loss and consistency).
Vivo adopts an improved version of Option 1: the single stock field is split into multiple fields to reduce row‑lock contention.
For batch claim (one‑click multiple coupons), performance is maintained by:
Batch insertion of coupon records (single I/O operation per user).
Limiting the maximum number of coupons per request.
Distributed‑lock keys for batch claims are generated per coupon type (e.g., userId+A_id , userId+B_id , …). All locks must be acquired; otherwise, the request waits or fails, preventing over‑claim.
Idempotency is guaranteed by a unique index on the coupon table, ensuring repeated requests produce the same result.
3.2.2 Targeted issuance
Used for large‑scale (up to billions) background distributions. Optimizations include removing transactions, lightweight validation, batch inserts, and configurable parameters (batch size, read‑batch size, message‑center payload size).
3.2.3 Code redemption
External marketing coupons are redeemed via codes exported from the backend. Security focuses on code validation to prevent reuse or malicious redemption.
3.3 Fine‑grained marketing capabilities
Tag‑based configurations enable personalized coupon delivery (real‑time and near‑real‑time tags). Visual diagrams illustrate the precise targeting flow.
3.4 Coupon‑product relationship
Coupons can be linked to all products, a blacklist, a whitelist, or a super‑blacklist (global). Future plans include category‑level associations.
3.5 High‑performance guarantees
Multi‑level caching (local + Redis) to reduce DB pressure and handle traffic spikes.
Read‑write splitting: writes go to the primary DB, reads are served by replicas with sub‑millisecond lag.
Circuit‑breaker isolation for third‑party dependencies.
Redundant coupon rule fields in the user‑coupon table to avoid extra joins.
Conclusion and outlook
The non‑downtime migration has kept the service stable for over two years, supporting Vivo Mall’s projected growth for the next 3‑5 years. The system is now decoupled, enabling faster iteration, and provides a comprehensive coupon capability. Future work aims to expose the coupon platform as a unified service for other internal businesses.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
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.