秒杀整体的技术难点

首先我就用华为官网 来说明秒杀的 整体流程,在华为官网某个秒杀场次点击商品信息

在这里插入图片描述我们就会跳转到商品详情页中来,具体这里的技术难点 我上一篇文章也说了, 然后点击 立即抢购
在这里插入图片描述

点击抢购 到达商品确认页--->之后点击下单 付款

在这里插入图片描述

也就是秒杀这里的业务流程就是(在某个活动下选择 某个场次 ,在某个场次下选择具体的商品,比如 618活动选择12 点到2点的场次, 在12点到2点的场次下选择 华为Pro20) 
(活动--->场次---->具体的商品)  点击商品---->商品详情页---->(立即抢购)商品确认页---------->{确认下单}
这就是秒杀这里的业务流程

在这里插入图片描述

秒杀的业务特点就是

在这里插入图片描述

呢么 在秒杀中我们应该注意一些什么技术问题呢?

在这里插入图片描述

商品详情页就是 之前说过了 采用nignx+lua+本地缓存 +redis 实现三级缓存策略
  .对用户的频率实现限制  不能让用户频繁访问 

秒杀 1.高并发解决超卖问题 首先我们要明白超卖问题是怎么产生的

--- table Info  我们的表结构
 CREATE TABLE `tb_product_stock` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `product_id` bigint(32) NOT NULL COMMENT '商品ID',
  `number` INT(8) NOT NULL DEFAULT 0 COMMENT '库存数量',
  `create_time` DATETIME NOT NULL COMMENT '创建时间',
  `modify_time` DATETIME NOT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_pid` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品库存表';
	
	//  ProductStock  pojo 

class ProductStock {
    private Long productId; //商品id
    private Integer number; //库存量

    public Long getProductId() {
        return productId;
    }

    public void setProductId(Long productId) {
        this.productId = productId;
    }

    public Integer getNumber() {
        return number;
    }

    public void setNumber(Integer number) {
        this.number = number;
    }
}
-------------<<<< 不考虑并发的时候 我们(select )查库存--->(update) 更改库存--->(insert ) 新增订单  
 多线程并发情况下,会存在超卖的可能。
 /**
     * 更新库存(不考虑并发)
     * @param productId
     * @return
     */
    public boolean updateStockRaw(Long productId){
 	//  查库存
        ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId}", productId);
        if (product.getNumber() > 0) {
    // 更改
            int updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId}", productId);
            if(updateCnt > 0){    //更新库存成功
                return true;
            }
        }
        return false;
    }

在这里插入图片描述

看以上的图 假设线程1 和线程2 同时查询到了 此时的库存有100个 
线程1 查询 100库存  进行update 更改库存(扣减库存)  更新为99
如果线程1 此时由于网络原因阻塞了, 此时
线程2 查询 100库存  进行update 更改库存(扣减库存) 更新为99,
因为在线程1 没有更新结束的时候 线程2就开始了查询 这样就发生了超卖 ,
我卖了2件商品 但是库存中只是扣减了一次


我们可以使用mysql的悲观锁来解决  select ... for update 
使用mysql 的select ...for update 悲观锁来解决超卖问题  悲观锁具有排他性
我当前的事务没有提交或者回滚, 你其他线程是不可以操作这一条数据的
/**
     * 更新库存(使用悲观锁)
     * @param productId
     * @return
     */
    public boolean updateStock(Long productId){
        //先锁定商品库存记录
        ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId} FOR UPDATE", productId);
        if (product.getNumber() > 0) {
            int updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId}", productId);
            if(updateCnt > 0){    //更新库存成功
                return true;
            }
        }
        return false;
    }
    /**
     * 下单减库存---------------->乐观锁  我们也可以使用Mysql 的乐观锁   ci
     * @param productId
     * @return
     */
    public boolean updateStock(Long productId){
        int updateCnt = 0;
        while (updateCnt == 0) {
            ProductStock product = query("SELECT * FROM tb_product_stock WHERE product_id=#{productId}", productId);
            if (product.getNumber() > 0) {
            ....................  这里 我们更改的时候加上 之前查询的数量如果是100的化 就更改 ,  或者加个版本号 或者加上uuid 
                updateCnt = update("UPDATE tb_product_stock SET number=number-1 WHERE product_id=#{productId} AND number=#{number}", productId, product.getNumber());
                if(updateCnt > 0){    //更新库存成功
                    return true;
                }
            } else {    //update  fill 更改失败
                return false;
            }
        }
        return false;
    }
1.  无论是乐观锁还是悲观锁 我们都要操作db, 都要上锁 会影响性能的  而且我们db的性能是优先的
比如说1w个人来抢购,商品有100个, 就会有1w个人来操作db  ,但是我此时只想让100 个人操作db,不让(1w-100)个人操作db  
我们可以采用redis 做预热

在这里插入图片描述

我们同样可以使用本地缓存 标志位true 加上redis 做预热来解决当前性能问题  这样我们的查询db 只会查询一部分 减少了db的压力

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值