What problems should be paid attention to in seckill and how to solve them

1. When conducting seckill activities, you need to pay attention to the following issues:

  1. Oversold problem: Lightning flash products may be oversold, that is, the inventory quantity exceeds the actual sellable quantity, which may lead to problems such as failure to pay normally or order cancellation. Therefore, it is necessary to ensure that the inventory quantity can be accurately controlled during the flash sale process to avoid overselling problems.
  2. High concurrency issues: Lightning deals usually attract a large number of users to rush to buy at the same time, which may lead to high system concurrency, cache failure, database breakdown and other problems. Therefore, it is necessary to take corresponding measures, such as optimizing the system architecture, increasing the cache, and strengthening the separation of reading and writing of the database, etc., to deal with high concurrency issues.
  3. Verification code security issues: In order to prevent malicious attacks or technical means from participating in flash sales, a verification code mechanism can be set. The verification code should be generated by the server, must be unique, and must not be mixed with other places on the website. In addition, the issuance of the verification code needs to have enough time to judge, so as to prevent it from being obtained in advance.
  4. Inventory control: For the inventory control of flash sale activities, it is necessary to use an in-memory database (such as redis) for fast data reading and writing to ensure the real-time and accuracy of inventory data.
  5. User experience: When designing and implementing seckill activities, user experience also needs to be considered, such as page loading speed, clarity and accuracy of product information, diversity and security of payment methods, etc., to ensure that users can participate smoothly and happily Spike activity.
  6. Purchase restriction problem: In order to prevent users from snapping up maliciously, purchase restrictions can be imposed on each user, such as each user can only purchase a certain amount of goods, or can only participate in one flash sale within a certain period of time, etc.
  7. After-sales service: The seckill activity may generate a large number of orders and inquiries, and it is necessary to prepare for after-sales service in advance, such as order processing, logistics distribution, return and exchange services, etc., to avoid problems such as untimely order processing and poor after-sales service.

2. Oversold problem

1. cause

The problems of seckill and overselling are caused by a large number of requests being sent to the server at the same time in a high-concurrency environment. In the case that the sales quantity of the seckill product is greater than its inventory quantity, the oversold problem will occur.

2. Use semaphore to solve

The following is an example of an oversold problem based on SpringBoot’s seckill activity:

In this example, we use SpringBoot's scheduled task scheduling function to execute the seckill activity on the hour every day. Before starting seckill, we need to control the amount of concurrent access, so we use Semaphore semaphore to control. Specifically, we use the tryAcquire() method to acquire the semaphore. If the acquisition is successful, it means that no other users are currently accessing the system, and the seckill activity can be started. In the seckill activity, we first update the product inventory to 0, indicating that the seckill can be started, then generate an order and save it in the database, and finally release the semaphore to allow other users to access the system. If it is blocked while acquiring the semaphore, an InterruptedException needs to be thrown and the current thread terminated.

@Service  
public class SeckillService {
    
      
  
    @Autowired  
    private ProductRepository productRepository;  
  
    @Autowired  
    private OrderRepository orderRepository;  
  
    @Autowired  
    private Semaphore semaphore;  
  
    @Scheduled(cron = "0 0 0 * * *") // 每天整点秒杀开始  
    public void startSeckill() {
    
      
        List<Product> products = productRepository.findAllBySeckillStatusAndSeckillEndTimeBefore(ProductStatus.SECKILL_STATUS_OPEN, new Date());  
        for (Product product : products) {
    
      
            try {
    
      
                // 获取信号量,控制并发访问  
                if (semaphore.tryAcquire()) {
    
      
                    // 更新商品库存为0,表示可以开始秒杀  
                    productRepository.updateSeckillStatusAndStock(product.getId(), ProductStatus.SECKILL_STATUS_SECKILLING, 0);  
                    // 生成订单,并保存到数据库中  
                    orderRepository.save(new Order(product, 1));  
                    // 释放信号量,允许其他用户访问  
                    semaphore.release();  
                }  
            } catch (InterruptedException e) {
    
      
                Thread.currentThread().interrupt();  
            }  
        }  
    }  
}  
}

3. Use optimistic locking to solve

In this example, we use the mechanism of optimistic locking to solve the problem of flash sales oversold. Specifically, we first obtain the inventory quantity of the current product, and then determine whether the inventory is sufficient. If the inventory is sufficient, update the product inventory to 0, indicating that the seckill has been successful, and generate an order and save it in the database. If the inventory is insufficient, it means that the current seckill has failed and you need to try the seckill again. In this process, we used methods such as timed tasks to execute the seckill operation again after a period of time until it succeeded.

@Service  
public class SeckillService {
    
      
  
    @Autowired  
    private ProductRepository productRepository;  
  
    @Autowired  
    private OrderRepository orderRepository;  
  
    @Scheduled(cron = "0 0 0 * * *") // 每天整点秒杀开始  
    public void startSeckill() {
    
      
        List<Product> products = productRepository.findAllBySeckillStatusAndSeckillEndTimeBefore(ProductStatus.SECKILL_STATUS_OPEN, new Date());  
        for (Product product : products) {
    
      
            // 获取当前商品的库存数量  
            int stock = productRepository.findByProductId(product.getId()).getStock();  
            // 判断库存是否足够  
            if (stock >= 1) {
    
      
                // 更新商品库存为0,表示已经秒杀成功  
                productRepository.updateSeckillStatusAndStock(product.getId(), ProductStatus.SECKILL_STATUS_SECKILLED, 0);  
                // 生成订单,并保存到数据库中  
                orderRepository.save(new Order(product, 1));  
            } else {
    
      
                // 库存不足,当前秒杀失败,需要重新尝试秒杀  
                // 可以使用定时任务等方式,在一段时间后再次执行秒杀操作  
            }  
        }  
    }  
}  
}

4. Use pessimistic locking to solve

In this example, we use the pessimistic locking mechanism to solve the oversold problem of flash sales. Specifically, we first obtain the inventory quantity of the current product and perform a lock operation. Here the ReentrantLock class is used for locking operations. If the inventory is sufficient, update the product inventory to 0, indicating that the seckill has been successful, and generate an order and save it in the database. If the inventory is insufficient, it means that the current seckill has failed and you need to try the seckill again. In this process, we used methods such as timed tasks to execute the seckill operation again after a period of time until it succeeded.

@Service  
public class SeckillService {
    
      
  
    @Autowired  
    private ProductRepository productRepository;  
  
    @Autowired  
    private OrderRepository orderRepository;  
  
    @Scheduled(cron = "0 0 0 * * *") // 每天整点秒杀开始  
    public void startSeckill() {
    
      
        List<Product> products = productRepository.findAllBySeckillStatusAndSeckillEndTimeBefore(ProductStatus.SECKILL_STATUS_OPEN, new Date());  
        for (Product product : products) {
    
      
            // 使用悲观锁,获取当前商品的库存数量,并进行加锁操作  
            Lock lock = new ReentrantLock();  
            synchronized(lock) {
    
      
                int stock = productRepository.findByProductId(product.getId()).getStock();  
                if (stock >= 1) {
    
      
                    // 更新商品库存为0,表示已经秒杀成功  
                    productRepository.updateSeckillStatusAndStock(product.getId(), ProductStatus.SECKILL_STATUS_SECKILLED, 0);  
                    // 生成订单,并保存到数据库中  
                    orderRepository.save(new Order(product, 1));  
                } else {
    
      
                    // 库存不足,当前秒杀失败,需要重新尝试秒杀  
                    // 可以使用定时任务等方式,在一段时间后再次执行秒杀操作  
                }  
            }  
        }  
    }  
}  
}

3. Solution to the high concurrency problem of seckill

Seckill is a highly concurrent operation, and it is necessary to ensure the correctness and reliability of the system when performing the Seckill operation. The following are several solutions to the high concurrency problem of seckill:

  1. Use asynchronous operations: In seckill operations, you can use asynchronous operations to reduce the number of accesses to the database, thereby improving the concurrency of the system. For example, you can use the @Async annotation to encapsulate the seckill operation as an asynchronous method, and use the @Scheduled annotation to perform asynchronous operations in scheduled tasks.
  2. Use cache: In seckill operations, you can use cache to reduce the number of accesses to the database, thereby improving the concurrency of the system. For example, you can use the @Cacheable annotation to cache the result of the seckill so that you can quickly find the result in the next seckill operation.
  3. Use distributed locks: In seckill operations, distributed locks can be used to ensure that only one user can perform seckill operations within the same second. For example, you can use the @Lock annotation to acquire distributed locks, and perform spike operations after acquiring the locks.
  4. Use the database partition table: In the seckill operation, you can use the database partition table to disperse the data into different data partitions, thereby reducing the number of accesses to the database and improving the concurrency of the system.
  5. Optimize database query: In the seckill operation, you can optimize the database query to improve the concurrency capability of the system. For example, you can use the @Query annotation to customize query statements to better utilize the concurrency capabilities of the database.

4. Security issues of seckill verification code

In this example, we use SpringBoot's scheduled task scheduling function to execute the seckill activity on the hour every day. Before starting the seckill, we generated a randomly generated captcha and saved it to the database. Then, we wait for the user to enter a captcha, and use the captcha generator to verify that the captcha entered by the user is correct. If the verification is successful, update the product inventory to 0, indicating that the seckill can start, and generate an order and save it in the database. If the captcha verification fails, it means that the user's request is invalid.

@Service  
public class SeckillService {
    
      
  
    @Autowired  
    private ProductRepository productRepository;  
  
    @Autowired  
    private OrderRepository orderRepository;  
  
    @Autowired  
    private CaptchaGenerator captchaGenerator;  
  
    @Scheduled(cron = "0 0 0 * * *") // 每天整点秒杀开始  
    public void startSeckill() {
    
      
        List<Product> products = productRepository.findAllBySeckillStatusAndSeckillEndTimeBefore(ProductStatus.SECKILL_STATUS_OPEN, new Date());  
        for (Product product : products) {
    
      
            // 生成验证码,并保存到数据库中  
            String captcha = captchaGenerator.generateCaptcha();  
            productRepository.updateSeckillCaptcha(product.getId(), captcha);  
            // 等待用户输入验证码,并进行验证  
            Scanner scanner = new Scanner(System.in);  
            System.out.println("请输入验证码:");  
            String inputCaptcha = scanner.nextLine();  
            if (captchaGenerator.validateCaptcha(inputCaptcha)) {
    
      
                // 验证成功,开始秒杀操作  
                try {
    
      
                    // 更新商品库存为0,表示可以开始秒杀  
                    productRepository.updateSeckillStatusAndStock(product.getId(), ProductStatus.SECKILL_STATUS_SECKILLING, 0);  
                    // 生成订单,并保存到数据库中  
                    orderRepository.save(new Order(product, 1));  
                } catch (Exception e) {
    
      
                    System.out.println("秒杀操作失败:" + e.getMessage());  
                }  
            } else {
    
      
                System.out.println("验证码验证失败!");  
            }  
        }  
    }  
}  
}  

Guess you like

Origin blog.csdn.net/lovoo/article/details/131510006