preamble
I've done a lot of marketing in my work over the past few years, and whether it's e-commerce business, payment business, or credit business, marketing is essential throughout the business development process. If the pre-marketing campaign is in place, it will bring a wave of traffic to the business. Then as a technology, how to catch this wave of traffic, rather than the service is hit hanging. Today, the big factory staff, hand in hand to teach you to develop a high concurrency, high availability of marketing activities.
experience for oneself
Click on me - Medical Examination Address
Click me - github source
professional work
Any technology divorced from the business is useless, so let's start with a brief introduction to the business.
The business wants our users to convert as high as possible in scenarios such as buying a product, placing an order and paying for it. Then to reward and incentivize users, theWe're hoping that with some couponsWe have a number of different ways to incentivize users who meet our rules to place orders, make payments, borrow money, make purchases, and other subsequent actions.
For example, if a user meets the rules of our campaign, the first step is to show him the offer, motivate him to take the next step, complete the task, and then give him the prize, write-offs and other follow-up actions.
Calibration of lottery eligibility
So based on the above analysis of our business, our first step is that the user comes in, we query the activity, and verify that the user is eligible to participate in the activity. If there is more than one activity, we select an activity for the user to participate in according to the business rules.
Then this is the starting point, the first step in our marketing campaign. If millions and millions of users come in at once, and we go to query the database for campaign information, and check the rules, our database will instantly collapse. So our core idea is:Tier-by-tier diversion and gradual decentralization of flows. ByBackup, flow limiting, downgrading, fusingand other means to enhance availability.
The first is to add cache, for some static pages, css, js and other files, can be placed in the client cache or CDN. For activity information and rules, before the activity goes online, we cache the information into redis. When the user comes in, we directly fetch the activity information from redis and calculate the activity rules without interacting with the database. Finally, we evaluate the activity qps, downgrade and limit the flow, and if the flow is too large, we directly intercept it to prevent the system from avalanche.
public MktActivityInfo checkActivityRule(String phone) {
// through (a gap)redisFetch from cache
MktActivityInfo activityInfo = ();
if (activityInfo == null || (())) {
return null;
}
ActivityRuleContext context = new ActivityRuleContext();
(phone);
// redisFetch from cache
List<MktActivityRule> mktActivityRules = (());
for (MktActivityRule mktActivityRule : mktActivityRules) {
BaseRuleService baseRuleService = (());
if (baseRuleService == null || !(context)) {
return null;
}
}
return activityInfo;
}
a raffle
Usually when you arrive at a sweepstakes, you basically complete the previous tasks, such as paying, placing an order, etc., and eventually qualify for the sweepstakes
- Inventory reduction. Cache the inventory information of the prizes into redis in advance, for example, 100 prizes are cached into redis. If there are 100W people to grab 100 prizes, only 100 people will pass the redis check in the end.
Long num = (CACHE_MKT_ACTIVITY_PRIZE_NUM, stringRedisTemplate);
if (num == null || num < 0) {
// Add the redis inventory back in, either way, depending on business requirements.
(CACHE_MKT_ACTIVITY_PRIZE_NUM, stringRedisTemplate); }
throw new RuntimeException("Insufficient redis inventory - " + ERROR_MSG);
}
- Depending on the business scenario, if it is not a sure winner. Before reducing the inventory, do a random number. If outside the random number, directly return "prize is taken", to limit most of the traffic into the redis inventory reduction
int seed = ().nextInt(0, 100) + 1; // 1-100
int random = ((CACHE_MKT_ACTIVITY_PRIZE_RANDOM, stringRedisTemplate));
if (seed > random) {
//("Random proportions intercepted seed = {}, random = {}", seed, random);
throw new RuntimeException("Randomized Proportionality Intercept - " + ERROR_MSG);
}
-
abort and retry
Failure to retry affects system performance, and the more retries there are, the greater the impact on system performance.
During the lottery process, from the lottery information verification to the deduction of inventory, the winning information into the warehouse, any part of the abnormal or failed, we will not retry, all as a non-winning treatment. -
Preventing the overissuance of prizes
Generally we go through optimistic locks, pessimistic locks, and distributed locks. Among them optimistic locks are the most efficient.
The following sql is not a standard optimistic lock; standard optimistic locks use a version field to determine this. However, the following sql is a good solution to the problem of optimistic locks being prone to failure
update mkt_activity_prize set num = num - 1 where num >= 1
// 4. the real database to reduce the inventory, and insert the award record
// If the redis pre-decrement succeeds, there is a high probability that it will succeed and basically not fail. If it fails, give up and retry. Failure to retry affects the performance of the system.
Boolean execute = (status -> {
// 4.1 Deducting inventory
Integer update = ((), ());
if (update == null || update <= 0) {
//("mysql inventory deduction failed update = {}", update); //("mysql inventory deduction failed update = {}", update); }
throw new RuntimeException("mysql Inventory deduction failed - " + ERROR_MSG);
}
// 4.2 Inserting the prize issuance record
MktActivityPrizeGrant grant = buildMktActivityPrizeGrant(phone, activityPrize);
Integer insert = (grant);
if (insert == null || insert <= 0) {
//("mysql failed to insert a prize record insert = {}", insert);
throw new RuntimeException("mysql insert prize record failed - " + ERROR_MSG);
}
return true.
}).
Then we can see from the above steps, in the real database to reduce inventory, random interception + redis inventory reduction has helped us to intercept most of the traffic, only a small part of the traffic will enter our real inventory reduction link. If the flow of inventory reduction is still particularly large, we can also adjust the random ratio column, at the same time, inventory reduction can be put into the mq, directly asynchronous issuance of prizes, basically less than the entire process will not interact with the database, the bottleneck point can be said to be almost non-existent. This architecture, support million, ten million qps no problem at all.
ultimate
In this paper, based on real business scenarios, a detailed analysis of a marketing campaign from the technical point of view of how to design and plan to achieve true high concurrency, high availability, to support the stable operation of the business. Which involves a lot of technical points or more, a lot of details are not listed, including how to ensure that redis inventory and mysql consistent, if the business in the activity want to modify the inventory how to do, how to ensure that not repeated to receive and so on.
Strongly recommend that you have the time to realize a version of their own, some of the details are still very test of skill, the realization of the down, there must be a lot of gains, thank you.