1. Business background

Coupon is a common means of marketing in e-commerce. It has the characteristics of flexibility. It can not only be used as the carrier of promotion activities, but also an important drainage entrance. Coupon system is an important part of the marketing module of Vivo Mall. As early as 15 years ago, when Vivo Mall was still a single application, coupon was one of the core modules. With the development of the mall and the increase of the number of users, the coupon service has been split, the establishment of an independent coupon system, to provide universal coupon service. At present, the coupon system covers the coupon of four core points: creation, hair, use, plan.

  • ** “create” ** refers to the creation of coupons, including the configuration of voucher rules and use threshold.

  • ** “hair” ** refers to the issuance of coupons, coupon system provides a variety of ways to issue coupons, to meet the different groups of active and passive distribution.

  • ** “use” refers to the use of coupons, including forward purchase of goods and the return of coupons after a reverse refund.

  • ** “count” ** refers to the statistics of coupons, including the number of coupons issued, the number of coupons used, the goods used and other data summary.

Vivo mall coupon system in addition to providing common coupon promotion play, but also in the form of coupons as a carrier of some other activities or assets, such as mobile phone goods in the value of new, in-purchase benefits, cooperation with external advertisers to issue coupons, etc.

The following is the vivo mall coupon part of the scene display:

Ii. System architecture and change

Coupons were originally coupled to malls in a system. With the continuous development of Vivo Mall, marketing activities to increase, coupon use more scenes, coupon system gradually began to “inadequate”, exposed a lot of problems:

  • The issuance of massive coupons has reached the storage bottleneck of coupon single library and single table.

  • The high coupling with the mall system directly affects the performance of the whole station interface.

  • Coupon iteration is limited to the store version schedule.

  • For multi-category coupons, there is no technical level of precipitation of general coupon ability.

In order to solve the above problems, the coupon system has been independent for 19 years, providing universal coupon service. After independence, the system architecture is as follows:

Coupon system independent migration scheme

How to migrate coupons out of the mall system and integrate with existing businesses and historical data is also a technical challenge. There are two options for system migration: shutdown migration and no shutdown migration.

We use the non-stop migration solution:

  • Before migration, the operation stops background operations related to coupons to avoid generating static data on coupons.

Static data: the data generated in the background of the coupon, has nothing to do with the user.

Dynamic data: coupon data related to users, including vouchers received by users, voucher and order relationship data, etc.

  • Configure the current database switch for single write, that is, coupon data is written to the mall library (old library).

  • Coupon system goes live, and static data is migrated through scripts. After the migration, verify the accuracy of static data migration.

  • Configure the current database switch to double write, that is, online data is written to the store library and the new coupon library. At this time, the data source provided by the service is still the mall library.

  • Migrate dynamic data. After the migration, verify the accuracy of the dynamic data migration.

  • The data source provided by the service is switched to the new library. Verify that the service is correct and switch back to the mall data source if there is a problem.

  • Close double write, the migration of coupon system is complete.

The request topology of the coupon system after migration is as follows:

Three, system design

3.1 Coupon classification table

As the number of coupons issued is increasing, the single table has reached a bottleneck. In order to support the development of the business, comprehensive consideration, the user coupon data for the database table.

Key words: technology selection, sub-database sub-table factor

Sub-table has a mature open source solution, here do not do too much introduction. Referring to the previous project experience, the self-developed framework provided by the company’s middleware team was adopted. The principle is to introduce the self-developed MyBatis plug-in, calculate different library table suffix according to the customized routing policy, and locate to the corresponding library table.

The user coupon is associated with the user ID, and the user ID is an important field throughout the system, so the user ID is used as the routing factor of the database table. In this way, the same user can be routed to the same database table, which is conducive to data aggregation and user data query.

Assuming that N libraries and M tables are divided, the routing policy for dividing libraries and tables is:

DatabaseSuffix databaseSuffix = hash(userId)/M %N

TableSuffix tableSuffix = hash(userId) % M

3.2 Design of coupon distribution

In order to meet the needs of different scenarios, the coupon system provides three coupon issuing methods: unified coupon interface, directional coupon issuing in the background, coupon code exchange issuance.

3.2.1 Unified coupon interface

Ensure the accuracy of coupon verification

When receiving coupons, it is necessary to strictly check whether various attributes of coupons are met, such as receiving objects and various restrictions. Among them, the more critical is the inventory and the quantity of check. Because in the case of high concurrency, it is necessary to ensure the accuracy of the quantity check, otherwise it is easy to cause users to overdraw.

In this scenario, user A initiates two consecutive requests to receive coupon C, and coupon C restricts each user to receive one coupon. The first request passes the verification of the number of coupons, and if there is no restriction, the second request will also pass the verification of the number of coupons. In this way, user A will receive two coupons C successfully, resulting in overpayment.

In order to solve this problem, coupon is a distributed locking scheme, the implementation of distributed locking depends on Redis. Before verifying the number of coupons issued by the user, try to obtain the distributed lock, and release the lock after the coupon is issued successfully, so as to ensure that the user will not overclaim the same coupon. In the above scenario, after A user successfully obtains A distributed lock on the first request, the obtained distributed lock is released until the first request succeeds or the release times out. Otherwise, the user fails to obtain the distributed lock on the second request. In this way, user A can obtain only one distributed lock successfully.

Inventory deduction

Coupons to carry out inventory deduction, common inventory deduction scheme has two kinds:

** Option 1: ** Database deductions.

When inventory is deducted, the inventory field in the database is updated directly.

The advantage of this scheme is that it is simple and convenient, and real-time inventory can be obtained by checking the inventory directly. And the database transaction guarantee, do not consider the problem of data loss and inconsistency.

The disadvantages are also obvious. There are mainly two points:

1) Inventory is a single field in the database. All requests need to wait for a row lock when the inventory is updated. Once the concurrency gets high, there will be a lot of requests blocking here, causing requests to time out and the system to avalanche.

2) Frequent requests to the database are time-consuming and will occupy a large number of database connection resources.

** Scheme 2: ** Implement inventory deduction operation based on Redis.

Put the inventory in the cache and use redis’ Incrby feature to deduct the inventory.

The advantage of this scheme is that it breaks through the bottleneck of database, has high speed and high performance.

The disadvantage is that the system process will be more complex, and need to consider cache loss or downtime data recovery problems, easy to cause inconsistent inventory data.

Considering the current and foreseeable future traffic peak of the coupon system, system maintainability and practicability, the coupon system adopts the improvement plan of the first plan. The improvement scheme is to disperse the single inventory field into multiple inventory fields to disperse the database row lock and reduce the bottleneck of the database row lock in the case of large amount of concurrency.

After the inventory number is updated, the inventory will be evenly divided into M copies and initialized to update the inventory record form. The user receives the coupon and randomly selects a certain inventory field (M in total) that has been allocated in the inventory record table for update. The successful update means the inventory deduction has been successful. At the same time, the scheduled task periodically synchronizes the received inventory. Compared with scheme 1, this scheme breaks through the bottleneck limit of database single row lock, and the implementation is simple, without considering the problem of data loss and inconsistency.

One key to get more than one ticket

In the coupon receiving scenario of the connected business party, a user can receive multiple coupons with one click. Therefore, the unified coupon issuing interface needs to support one-click coupon issuing by users. In addition to receiving multiple coupons of the same template, it also supports receiving multiple coupons of different templates. Generally speaking, one key to get more than one voucher refers to the receipt of different voucher template. During the implementation, the following points need to be noted:

1) How to ensure performance

Take multiple coupons. If each coupon is checked, inventory deducted and put into storage respectively, the bottleneck of interface performance is stuck in the number of coupons. The more the number is, the performance plummets. So in the case of a large number of vouchers, how to ensure high performance? Two main measures will be taken:

A. Batch operations.

From the point of view of the process of issuing coupons, the bottleneck lies in the warehousing of coupons. Coupons are issued in real time (if asynchronous, coupons can not be sent to the user account in real time, which will affect the user experience and the conversion rate of coupons). The more coupons, the more IO times when entering the database, and the worse the performance. Batch storage can ensure that the number of IO with the database is only once, not affected by the number of coupons. As mentioned above, the user’s coupon data has been classified into database tables, and the coupon assets of the same user are stored in the same database table, so the same user can realize batch warehousing.

B. Limit the number of coupons issued at a single time.

Set the threshold and return directly after the number is exceeded to ensure that the system is within the safe range.

2) Ensure that users will not overtake in high concurrency situations

If the user initiates A request in the mall and gets four coupons A/B/C/D with one button, and the activity system issues coupon A to the user at the same time, these two coupon requests are simultaneously. Coupon A is limited to one per user. According to the foregoing, distributed lock is adopted to ensure the accuracy of verification. The keys of the distributed lock requested twice are:

User id + A_id + B_id + C_id + D_id

User id + A_id

In this case, the distributed lock of the two requests does not work because the lock key is different, and there is still a possibility of error in the quantity check. In order to avoid the phenomenon of over-collar in the process of batch coupon, the acquisition of distributed lock is modified in the process of batch coupon. In the example above, four distributed locks need to be obtained in A batch to get four coupons A/B/C/D with one key. The lock key is:

User id + A_id

User id + B_id

User id + C_id

User id + D_id

Failure to acquire any of the locks indicates that the user is claiming one of the tickets at this time and needs to spin and wait (within the timeout period). The next step can be performed only after all distributed locks have been obtained.

Interface idempotence

The uniform coupon interface must be idempotent (idempotent: the result of one or more requests initiated by the user for the same operation is consistent). In the case of network timeout or abnormal, if the result of coupon issuing is not returned in time, the service party will enter the bank for coupon issuing and retry. If the interface is not idempotent, oversending may occur. Idempotent can be implemented in a variety of ways. Coupon systems use unique indexes in databases to ensure idempotent.

The coupon was originally not idempotent, and the table design did not take idempotent into account.

So the first question to consider is: on which table do you add a unique index?

There are no more than two options: an existing table or a new table.

  • Use existing tables, no need to add table associations. However, as mentioned above, because of the separation of database and table, a large number of tables need to add unique fields, and need to be compatible with historical data, it is necessary to ensure the uniqueness of the new fields of historical data.

  • The new table approach does not need to be compatible with historical data, but the drawbacks are obvious. Adding a layer of table association can have a significant impact on performance and existing logic. All in all, we chose to add unique fields to the existing tables to ensure better performance and subsequent maintenance.

** Second consideration: how to accommodate historical data and business parties? ** Historical data has added unique fields, which must be filled with unique values, otherwise the unique index cannot be added. We use a script brush to construct unique values and refresh them in each row of historical data. The business side with which the coupon has been connected does not pass in a unique code. In this case, the coupon side generates a unique code as an alternative to ensure compatibility.

3.2.2 Directed Issuance of coupons

Directional issuance of coupons is used for operation in the background to issue coupons to specific groups. Directional issuance of coupons can make up for users to take the initiative to get coupons, crowd coverage is not accurate, coverage is not wide. Through directional issuance of coupons, specific groups can be accurately covered and the conversion rate of orders can be improved. During the promotion period, the targeted coupons of a large range of people can also carry the dual tasks of activity push and discount promotion.

Directional issuance mainly lies in the circle selection of people and the design of issuance process. The overall process is as follows:

Directional issuance of coupons is different from the active issuance of coupons by users. The amount of directional issuance of coupons is usually very large (billion level). In order to support a large number of targeted issue, targeted issue has been optimized:

1) Remove transactions. The transaction logic is too heavy to be necessary for directed issuance. When issuing coupons fails, record the failed coupons to ensure that the failed coupons can be retried.

2) Lightweight check. Directional issuance limits the type of coupons and avoids the configuration that requires strict verification attributes. Different from the lengthy verification logic of users’ active coupons, the verification of directional coupons is very lightweight, which greatly improves the performance of coupons.

3) Batch insert. Batch coupon insertion reduces the number of DATABASE I/O, eliminates database bottleneck, and improves coupon issuance speed. Directional coupons are for different users, user coupons to do a sub-table, in order to achieve batch insert, need to calculate the memory of different users corresponding to the library table suffix, data collection and then batch insert, insert M times at most, M is the total number of library table.

4) Core parameters can be dynamically configured. For example, the number of coupons issued per time, the number of library reads per time, the number of users in the message body sent to the message center, etc., can control the peak speed and average speed of directed coupons.

3.2.3 Coupon code exchange

The issuing method of off-site marketing coupons is different from other coupons, which are exchanged through coupon codes. The coupon code is exported from the background and issued to the user through SMS or activity. The user can get the corresponding coupon after exchanging the coupon code. There are certain rules for the composition of coupon codes. On the basis of the rules, the security should be ensured. This security is mainly to ensure the accuracy of coupon code verification and prevent the re-exchange of redeemed coupon codes and the malicious exchange of invalid coupon codes.

3.3 Refined marketing ability design

Through the way of label combination configuration, coupons provide refined marketing capabilities to realize the thousands of faces of coupons. Tags can be classified as quasi-real-time or real-time. It is worth noting that some real-time tags require prerequisites for processing, such as user authorization for the region attribute.

Precise touch of coupons:

3.4 Relationship between coupons and commodities

The use of coupons needs to be associated with the goods, can be associated with all goods, also can be associated with part of the goods. In order to flexibly meet the configuration of coupons associated with the operation, the coupon system has two association methods:

A. Blacklist.

Available Items = All items – Blacklist items.

Blacklist applies to the use of a wide range of commodities coupon, all commodities excluded from the blacklist of commodities is the use of the scope of coupons.

B. Whitelist.

Available goods = whitelist goods.

The whitelist applies to the situation that the scope of commodities that can be used is relatively small, and the commodities that can be used are configured directly.

In addition, there is a super blacklist configuration, the blacklist and whitelist is only valid for a single ticket, the super blacklist is valid for all tickets. Current coupon system provider level association, subsequent coupons will support commodity classification dimension association, classification dimension + commodity dimension can be more flexible association of coupons and commodities.

3.5 High Performance

There are many coupon interconnection systems and high traffic scenarios. Therefore, the coupon external interface must ensure high performance and high stability.

Multistage cache

In order to improve the query speed, reduce the pressure on the database, and at the same time, in order to deal with the scene where instantaneous high traffic brings hot key (for example, switching traffic to the detailed page of a specific commodity and the detailed page of a hot activity commodity will bring instantaneous high traffic to the coupon system at the end of the live press conference), multi-level caching is adopted for coupons.

Database read/write separation

Coupons in addition to the above mentioned sub-database sub-table, on this basis also do read and write separation operation. The master database is responsible for executing the data update request, and then synchronizing the data changes to all the slave libraries in real time, sharing the query request with the slave library, and solving the problem of database write affecting the query. There is a delay in master-slave synchronization, which is less than 1ms under normal circumstances. There is a time-consuming process for coupon receiving or status change, and the master-slave delay is not perceived by users.

The circuit is disconnected from external interfaces

The coupon relies on the third-party system internally. In order to prevent the failure of the service of the dependent party, which leads to a chain effect and finally leads to the avalanche of coupon service, the coupon has isolated and fuses the external interface of dependence.

The user dimension coupon field is redundant

The query of user-related coupon data is one of the most frequent query operations of coupons. The user coupon data is divided into database and table, and the query cannot be associated with the coupon rule table. In order to reduce IO times, some coupon rule fields are redundant in the user coupon table. Coupon rule table fields, redundant fields can not be many, to do a good balance between the performance and the number of fields.

Iv. Summary and outlook

Finally, a summary of the coupon system:

  • Non-stop migration, smooth transition. Since independence has been stable operation for 2 years, the performance is enough to support vivo mall in the next 3-5 years of rapid development.

  • The system is decoupled and the iteration efficiency is greatly improved.

  • For business problems, the principle is to choose a suitable and practical solution.

  • Have perfect coupon business ability.

Outlook: At present, the coupon system mainly serves Vivo Mall. In the future, we hope to open the coupon ability and provide a general integrated coupon platform for other internal business parties.

Author: Yan Chao, Vivo Internet Development Team