Chapter IX traffic clipping technology

Question 1: Request an order can keep the brush caused by cattle as well as pressure on the server through a script

Such a restriction can be done only to get a user in the process of logical tokens in the token issuer spike

Question 2: Write a single logical interfaces with a single spike and the lower, of the redundant strong spike. Even if the activity does not start, it can be used as general merchandise orders. Trading system would cause no associated load

Resolution: introducing token spike, the spike into the single logical token generation here, so easy to separate after deployment.

1. to use the access token to avoid large single

Wind spike control and to manage the token authentication, the user avoid a large flow of operations performed at a single

Generating a token general than some of the inventory, such as double

First call / generatePromoToken, generate promoToken, then carry promoToken to the next one / createorder

(1) generating a token spike

public String generateSecondKillTocken(Integer itemId, Integer userId, Integer promoId, Integer amount) {
		// 1. check a single state, single commodity exists and whether the user is legitimate and whether the correct number of purchase
        ItemModel itemModel = itemService.getItemByIdInCache(itemId);
        if(itemModel == null){
            return null;
        }
        
        UserModel userModel = userService.getUserByIdInCache(userId);
        if(userModel == null){
            return null;
        }
        if(amount <= 0 || amount > 99){
            return null;
        }

        // check event information
        if(promoId != null){
            // (1) verify the existence of this correspondence activity for what goods
            if(promoId.intValue() != itemModel.getPromoModel().getId()){
            	return null;
                // (2) check whether the activities in progress
            }else if(itemModel.getPromoModel().getStatus().intValue() != 2) {
            	return null;
            }
        }
        // generate buying token, and store reids
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set("promo_token_"+promoId+"_"+itemId+"_"+userId, token);
        redisTemplate.expire("promo_token_"+promoId+"_"+itemId+"_"+userId, 5, TimeUnit.MINUTES);
        return token;
	}

(2) single authentication token

// single package request
    @RequestMapping(value = "/createorder",method = {RequestMethod.POST},consumes={CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId")Integer itemId,
                                        @RequestParam(name="amount")Integer amount,
                                        @RequestParam(name="promoId",required = false)Integer promoId,
                                        @RequestParam(name="token",required = false)String token,
                                        @RequestParam(name="promoToken",required = false)String promoToken) throws BusinessException {

    	UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
    	// spike token verification, compared with the value of redis
    	if(promoId!=null) {
    		if(promoToken!=null) {
    			String inRedisPromoToken = (String) redisTemplate.opsForValue().get("promo_token_"+promoId+"_"+itemId+"_"+userModel.getId());
    			if(!promoToken.equals(inRedisPromoToken)) {
    				throw new BusinessException (EmBusinessError.PARAMETER_VALIDATION_ERROR, "spike token validation failed");
    			}
    		} else {
    			throw new BusinessException (EmBusinessError.PARAMETER_VALIDATION_ERROR, "spike token validation failed");
    		}
    	}
    	
        // add water init state commodity stocks
        String stockLogId = itemService.initStockLog(itemId, amount);
        
        //OrderModel orderModel = orderService.createOrder(userModel.getId(),itemId,promoId,amount);
        // transactional message driven by a single, simultaneous or rollback message to determine the transmission state in accordance with callback
        boolean mqResult = mqProducer.transactionAsyncReduceStock(userModel.getId(),itemId,promoId,amount, stockLogId);
        if(!mqResult) {
        	throw new BusinessException (EmBusinessError.UNKNOWN_ERROR, "single failure");
        }
        return CommonReturnType.create(null);
    }

Question 3: Achieving spike token is defective, it can generate unlimited, so if there are over one hundred million users, generating affect system performance, but also can not grab a token of goods

Resolution: introducing spike gates, according to issue stock number of tokens corresponding to the flow rate control gates

(1) at the time of launch event, save the library to redis, the number of gates will also be saved to redis

public void publishPromo(Integer promoId) {
		。。。。。。。。。。。。。。。。。
		// inventory in sync to redis
		redisTemplate.opsForValue().getAndSet("promo_item_stock_"+promoDO.getItemId(), itemModel.getStock());
		// Save the number to spike gates redis
		redisTemplate.opsForValue().set("promo_door_count_"+promoId, itemModel.getStock().intValue()*5);
	}

(2) the token is generated before the number to check whether there are gates spike  

@Override
	public String generateSecondKillTocken(Integer itemId, Integer userId, Integer promoId, Integer amount) {
		// check whether the inventory is sold out
        if(redisTemplate.hasKey("promo_item_stock_invalid_"+itemId)) {
        	return null;
        }
		// 1. check a single state, single commodity exists and whether the user is legitimate and whether the correct number of purchase
        。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
        // Get the number of gates spike
        long result = redisTemplate.opsForValue().increment("promo_door_count_"+promoId, -1);
        if(result<0) {
        	return null;
        }
        // generate buying token, and store reids
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set("promo_token_"+promoId+"_"+itemId+"_"+userId, token);
        redisTemplate.expire("promo_token_"+promoId+"_"+itemId+"_"+userId, 5, TimeUnit.MINUTES);
        return token;
	}

Question 4: token can not cope with the influx of traffic surges, such as inventory itself is very large. In addition multiple inventories, limit the ability of multi-commodity token weak

Solution: the introduction of flood queue, the task will be submitted to the thread pool, the thread pool threads covered with executable tasks will be placed in the waiting queue, to do so would be tantamount to restricting the flow of concurrent users, making it waiting in the thread pool queue queuing process. Then the future is to enable the use of front-end user after the call controller can synchronize the results obtained

1 queuing times faster than the concurrent, if the wait for the lock, the thread exits. Another thread scheduling CPU, CPU context switching loss

For example: redis is single-threaded, but soon. Because redis is a memory operation, and there is no thread switch overhead on single thread

 

private ExecutorService executorService;
    
    @PostConstruct
    public void init() {
    	executorService = Executors.newFixedThreadPool(20);
    }

// single package request
    @RequestMapping(value = "/createorder",method = {RequestMethod.POST},consumes={CONTENT_TYPE_FORMED})
    @ResponseBody
    public CommonReturnType createOrder(@RequestParam(name="itemId")Integer itemId,
                                        @RequestParam(name="amount")Integer amount,
                                        @RequestParam(name="promoId",required = false)Integer promoId,
                                        @RequestParam(name="token",required = false)String token,
                                        @RequestParam(name="promoToken",required = false)String promoToken) throws BusinessException {
    	
		。。。。。。。。。。。。。。。。。。。。。。。。。。。。
    	// synchronous call the submit method thread pool
    	// congestion window to the waiting queue 20, a queue to flood, more than 20 of the queue to wait
    	Future<Object> future = executorService.submit(new Callable<Object>() {

			@Override
			public Object call() throws Exception {
				// add water init state commodity stocks
		        String stockLogId = itemService.initStockLog(itemId, amount);
		        
		        //OrderModel orderModel = orderService.createOrder(userModel.getId(),itemId,promoId,amount);
		        // transactional message driven by a single, simultaneous or rollback message to determine the transmission state in accordance with callback
		        boolean mqResult = mqProducer.transactionAsyncReduceStock(userModel.getId(),itemId,promoId,amount, stockLogId);
		        if(!mqResult) {
		        	throw new BusinessException (EmBusinessError.UNKNOWN_ERROR, "single failure");
		        }
				return null;
			}
    		
		});
    	
    	try {
    		// get method to get the results, the method will block until the task returns the result.
			future.get();
		} catch (InterruptedException | ExecutionException e) {
			throw new BusinessException(EmBusinessError.UNKNOWN_ERROR);
		}
        
        return CommonReturnType.create(null);
    }

  

Guess you like

Origin www.cnblogs.com/t96fxi/p/12099335.html