当前位置:网站首页>Design and implementation of secsha system

Design and implementation of secsha system

2022-07-05 23:12:00 Bald and weak.

Write it at the front

Second kill is no stranger to everyone , And it is a necessary skill point for e-commerce projects .
But the real secsha service is very complicated , Second kill has the characteristics of instant high concurrency , So solve the problem of instant high concurrency , Can solve the problem of second kill .
Today, we will decompose the complete implementation of secsha system , Let's study it together .
( Please correct any questions )

Precautions for seckill system

Single responsibility for service + Independent deployment

There are great risks in seckill service , Carelessness will cause service downtime or occupy a lot of server resources in an instant , therefore Seckill service must be deployed independently , And seckill service only does seckill function .

Seckill link encryption

Prevent malicious attacks , Prevent someone from simulating the seckill request, causing greater pressure on the server ;
Prevent link exposure , Prevent staff from killing goods in advance .

Stock preheating + Quick deduction

Second kill system reads more and writes less , We can preheat the total inventory first , Deposit in redis in , Use semaphores to control the number of seckill requests .

Dynamic and static separation

Use nginx Do a good job of separating the static from the dynamic , Ensure that static resources can directly request , Avoid consuming backend resources .( Now they are basically front and back-end separation projects , It's negligible here )

Malicious request interception

Identify the request of illegal attack and intercept , It can be intercepted from the gateway layer , Determine whether the user is logged in .

Flow peak shifting

By all means , Sharing traffic to a wider range of time points . For example, verification code 、 Add to cart , Add a few more steps .

Current limiting & Fuse & Downgrade

Front end current limiting + Back end current limiting .
Limit one click per second ; Limit the total amount ;
Back end fast failure 、 Degraded operation 、 Circuit breaker mechanism prevents avalanche .

Queue clipping

Second kill all successful products , Put it in the message queue , Then the consumer slowly creates orders and other logic .

Concrete realization

Current limiting fuse

Use sentinel Carry out current limiting
Detailed explanation sentinel: Traffic guard of distributed system

Queue clipping

Use rockerMQ perhaps rabbitMQ Peak clipping .

Stock preheating

Using scheduled tasks , Send the product information in advance 、 Commodity random code ( Prevent malicious attacks )、 Information such as commodity inventory is stored redis.

Pseudo code :

/** *  Cache the product information associated with the second kill activity  */
private void saveProductInfo(List<Product> products) {
    

    products.stream().forEach(products-> {
    
        // Get ready hash operation , binding hash
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(SECKILL_CHARE_PREFIX);
        products.getRelationSkus().stream().forEach(seckillSkuVo -> {
    
            // Generate random code 
            String token = UUID.randomUUID().toString().replace("-", "");
            String redisKey = seckillSkuVo.getPromotionSessionId().toString() + "-" + seckillSkuVo.getSkuId().toString();
            if (!operations.hasKey(redisKey)) {
     //  Prevent duplicate addition 
                // Cache our product information 
                SeckillSkuRedisTo redisTo = new SeckillSkuRedisTo();
                Long skuId = seckillSkuVo.getSkuId();
                //1、 First, check the basic information of the goods , Call remote service 
                R info = productFeignService.getSkuInfo(skuId);
                if (info.getCode() == 0) {
    
                    SkuInfoVo skuInfo = info.getData("skuInfo",new TypeReference<SkuInfoVo>(){
    });
                    redisTo.setSkuInfo(skuInfo);
                }

                //2、sku Second kill information 
                BeanUtils.copyProperties(seckillSkuVo,redisTo);

                //3、 Set the second kill time information of the current product 
                redisTo.setStartTime(session.getStartTime().getTime());
                redisTo.setEndTime(session.getEndTime().getTime());

                //4、 Set random code of goods ( Prevent malicious attacks )
                redisTo.setRandomCode(token);

                // serialize json Format deposit Redis in 
                String seckillValue = JSON.toJSONString(redisTo);
                operations.put(seckillSkuVo.getPromotionSessionId().toString() + "-" + seckillSkuVo.getSkuId().toString(),seckillValue);

                // If the commodity inventory information of the current session has been put on the shelf, it does not need to be put on the shelf 
                //5、 Use inventory as distributed Redisson Semaphore ( Current limiting )
                //  Use inventory as a distributed semaphore 
                RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + token);
                //  The number of goods can be killed in seconds as a semaphore 
                semaphore.trySetPermits(seckillSkuVo.getSeckillCount());
            }
        });
    });
}

Second kill

/** *  Second kill of goods ( The second kill begins ) * @param killId * @param key * @param num * @return */
@GetMapping(value = "/kill")
public String seckill(@RequestParam("killId") String killId,
                      @RequestParam("key") String key,
                      @RequestParam("num") Integer num,
                      Model model) {
    

    String orderSn = null;
    try {
    
        //1、 Determine whether to log in 
        orderSn = seckillService.kill(killId,key,num);
        model.addAttribute("orderSn",orderSn);
    } catch (Exception e) {
    
        e.printStackTrace();
    }
    return "success";
}
/** *  Second kill the current product ( The second kill begins ) * @param killId * @param key * @param num * @return */
@Override
public String kill(String killId, String key, Integer num) throws InterruptedException {
    

    long s1 = System.currentTimeMillis();
    // Get current user information 
    MemberResponseVo user = LoginUserInterceptor.loginUser.get();

    //1、 Get the details of the current second kill product from Redis In order to get 
    BoundHashOperations<String, String, String> hashOps = redisTemplate.boundHashOps(SECKILL_CHARE_PREFIX);
    String skuInfoValue = hashOps.get(killId);
    if (StringUtils.isEmpty(skuInfoValue)) {
    
        return null;
    }
    //( Validity test )
    SeckillSkuRedisTo redisTo = JSON.parseObject(skuInfoValue, SeckillSkuRedisTo.class);
    Long startTime = redisTo.getStartTime();
    Long endTime = redisTo.getEndTime();
    long currentTime = System.currentTimeMillis();
    // Judge whether the current second kill request is within the active time interval ( Validity of time )
    if (currentTime >= startTime && currentTime <= endTime) {
    

        //2、 Verify random codes and Commodities id
        String randomCode = redisTo.getRandomCode();
        String skuId = redisTo.getPromotionSessionId() + "-" +redisTo.getSkuId();
        if (randomCode.equals(key) && killId.equals(skuId)) {
    
            //3、 Verify whether the shopping quantity is reasonable and whether the inventory is sufficient 
            Integer seckillLimit = redisTo.getSeckillLimit();

            // Acquisition semaphore 
            String seckillCount = redisTemplate.opsForValue().get(SKU_STOCK_SEMAPHORE + randomCode);
            Integer count = Integer.valueOf(seckillCount);
            // Judge whether the semaphore is greater than 0, And you can't buy more than you have in stock 
            if (count > 0 && num <= seckillLimit && count > num ) {
    
                //4、 Verify that this person has bought ( Idempotent treatment ), If the second kill succeeds , Just take a seat .userId-sessionId-skuId
                //SETNX  Atomic treatment 
                String redisKey = user.getId() + "-" + skuId;
                // Set auto expiration ( End time - current time )
                Long ttl = endTime - currentTime;
                Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(redisKey, num.toString(), ttl, TimeUnit.MILLISECONDS);
                if (aBoolean) {
    
                    // A successful space occupation means that you have never bought , Distributed lock ( Acquisition semaphore -1)
                    RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + randomCode);
                    //TODO  Seckill success , Order quickly 
                    boolean semaphoreCount = semaphore.tryAcquire(num, 100, TimeUnit.MILLISECONDS);
                    // Guarantee Redis There is also a stock of goods 
                    if (semaphoreCount) {
    
                        // Create an order number and send the order information to MQ
                        //  Seckill success   Order quickly   Send a message to  MQ  The whole operation time is  10ms  about 
                        String timeId = IdWorker.getTimeId();
                        SeckillOrderTo orderTo = new SeckillOrderTo();
                        orderTo.setOrderSn(timeId);
                        orderTo.setMemberId(user.getId());
                        orderTo.setNum(num);
                        orderTo.setPromotionSessionId(redisTo.getPromotionSessionId());
                        orderTo.setSkuId(redisTo.getSkuId());
                        orderTo.setSeckillPrice(redisTo.getSeckillPrice());
                        rabbitTemplate.convertAndSend("order-event-exchange","order.seckill.order",orderTo);
                        long s2 = System.currentTimeMillis();
                        log.info(" Time consuming ..." + (s2 - s1));
                        return timeId;
                    }
                }
            }
        }
    }
    long s3 = System.currentTimeMillis();
    log.info(" Time consuming ..." + (s3 - s1));
    return null;
}

redisson Semaphore

redisson Use the total solution ——redisson Official documents + notes ( medium-length )

原网站

版权声明
本文为[Bald and weak.]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/186/202207052251547856.html