目录

Redis 秒杀

Mysql数据库设计

Mysql秒杀实现

Mysql+Redis秒杀实现


秒杀是一种高并发场景,通常指的是在短时间内(秒级别)有大量用户同时访问某个商品服务,争相抢购的情景。在这种情况下,系统需要处理大量并发请求确保公平性、一致性,并防止因并发而导致的问题例如超卖恶意请求等。以下是在高并发秒杀场景需要考虑的一些关键问题解决方案

  1. 超卖问题 大量用户同时抢购同一商品可能导致超卖(卖出超过库存数量)的问题。为了解决这个问题可以采用悲观锁或乐观锁的方式控制库存访问数据库的行级锁、分布式锁等技术可以用来防止超卖

  2. 性能优化并发场景下,系统性能是关键。使用缓存异步处理、CDN 加速等手段可以显著提升系统性能缓存可以存储商品信息用户状态等,减轻数据库压力异步处理可以将一些不需要即时返回结果操作异步执行,减轻请求响应时间

  3. 并发控制 在高并发场景下,为了防止系统崩溃服务可用需要对并发进行控制。可以使用队列限流技术确保系统在承受能力范围处理请求,防止系统负荷崩溃

  4. 秒杀令牌时间窗口 可以在系统中引入秒杀令牌,只有携带有效令牌用户才能参与秒杀。同时,可以设置一个时间窗口,只在特定的时间范围内允许秒杀操作有效控制请求的涌入。

  5. 用户鉴权防刷 针对恶意请求,需要进行用户鉴权,并采用防刷策略例如限制同一用户在短时间内的请求次数通过验证码方式增加用户请求的成本,防止恶意请求。

  6. 队列异步处理: 使用消息队列将用户的秒杀请求进行排队,然后异步处理。这样可以有效地削峰填谷,减轻系统瞬时的压力提高系统的容错能力

  7. 分布式事务 如果系统是分布式的,需要考虑分布式事务问题确保在秒杀过程中的各个阶段,包括扣减库存生成订单等,能够保持事务一致性

  8. 实时监控日志记录 在高并发场景下,实时监控是及时发现问题解决问题的关键。记录详细日志信息,包括用户请求日志、系统性能日志等,便于事后分析优化

Redis 秒杀

Mysql数据库设计

/*
SQLyog Community v11.26 (32 bit)
MySQL - 8.0.33 : Database - test
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`test` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */;

USE `test`;

/*Table structure for table `stock` */

DROP TABLE IF EXISTS `stock`;

CREATE TABLE `stock` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(20) DEFAULT NULL,
  `count` INT DEFAULT NULL,
  `create_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `stock` */

INSERT  INTO `stock`(`id`,`name`,`count`,`create_time`) VALUES (1,'apple',500,'2023-11-28 19:02:04'),(2,'huawei',500,'2023-11-28 19:02:26');

/*Table structure for table `stock_order` */

DROP TABLE IF EXISTS `stock_order`;

CREATE TABLE `stock_order` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(20) DEFAULT NULL,
  `price` INT DEFAULT NULL,
  `create_time` TIMESTAMP NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1729467951815541250 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `stock_order` */

/*Table structure for table `article_select` */

DROP TABLE IF EXISTS `article_select`;

/*!50001 DROP VIEW IF EXISTS `article_select` */;
/*!50001 DROP TABLE IF EXISTS `article_select` */;

/*!50001 CREATE TABLE  `article_select`(
 `a` bigint ,
 `b` varchar(11) ,
 `c` varchar(20) ,
 `d` bigint 
)*/;

/*View structure for view article_select */

/*!50001 DROP TABLE IF EXISTS `article_select` */;
/*!50001 DROP VIEW IF EXISTS `article_select` */;

/*!50001 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `article_select` (`a`,`b`,`c`,`d`) AS select `article`.`id` AS `id`,`article`.`name` AS `name`,`article`.`des` AS `des`,`article`.`categoryid` AS `categoryid` from `article` */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

Mysql秒杀实现

秒杀代码设计初步代码如下:

@RestController
public class MyController {

   
    @Autowired
    StockMapper stockMapper;

    @Autowired
    StockOrderMapper stockOrderMapper;

    @Transactional
    @GetMapping("/order/{id}")
    public String order(@PathVariable("id") Long id){
        Stock stock = stockMapper.selectById(id);
        Integer count = stock.getCount();
        if(count<=0){
            throw new RuntimeException("库存不足");
        }
        StockOrder stockOrder=new StockOrder();
        stockOrder.setName(stock.getName());
        stockOrderMapper.insert(stockOrder);

        UpdateWrapper<Stock> updateWrapper=new UpdateWrapper<>();
        updateWrapper.setSql("count = count - 1 where count > 0 and id ="+id); //在mysql这里执行时候数据库会加行锁,所以相对安全int update = stockMapper.update(null, updateWrapper);
        if(update<=0){
            throw new RuntimeException("库存不足");
        }
        return "success";
    }
}

由于业务代码直接mysql数据库进行交互mysql一秒支持的并发量低,性能较低,然后下面进行压测

压测得到的汇总报告下图

Mysql+Redis秒杀实现

使用redis修改代码如下

@RestController
public class MyController {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    StockMapper stockMapper;

    @Autowired
    StockOrderMapper stockOrderMapper;


    @PostConstruct
    public void init(){
        List<Stock> stocks = stockMapper.selectList(null);
        for (Stock stock : stocks) {
            stringRedisTemplate.opsForValue().set("product_"+stock.getId(),stock.getCount()+"");
        }
    }

    
    @GetMapping("/order/{id}")
    public String order(@PathVariable("id") Long id){
        Long decrement = stringRedisTemplate.opsForValue().decrement("product_" + id);
        if(decrement<0){
            stringRedisTemplate.opsForValue().increment("product_"+id);
            return "库存不足";
        }
        try {
           ((MyController)AopContext.currentProxy()).mys_order(id);
        }catch (Exception e){
            stringRedisTemplate.opsForValue().increment("product_"+id);
            return "库存不足";
        }
        return "购买成功";
    }
    @Transactional
    public void mys_order(Long id){
        Stock stock = stockMapper.selectById(id);
        if(stock.getCount()<=0){
            throw new RuntimeException("库存不足");
        }
        StockOrder stockOrder=new StockOrder();
        stockOrder.setName(stock.getName());
        stockOrderMapper.insert(stockOrder);

        UpdateWrapper<Stock> updateWrapper=new UpdateWrapper<>();
        updateWrapper.setSql("count = count - 1 where count > 0 and id ="+id); //在mysql这里执行时候数据库会加行锁,所以相对安全int update = stockMapper.update(null, updateWrapper);
        if(update<=0){
            throw new RuntimeException("库存不足");
        }
    }
}

压测结果吞吐量下图使用redis作为缓存相对于仅仅使用mysql数据吞吐量提升了不少,性能得到了提升

原文地址:https://blog.csdn.net/qq_43649937/article/details/134675795

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_49715.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注