基于SpringBoot的高并发秒杀(限时秒杀)

最近出于公司业务需要,做了拼团抢购,秒杀的业务。

秒杀系统场景特点

  • 秒杀时大量用户会在同一时间同时进行抢购,网站瞬时访问流量激增。
  • 秒杀一般是访问请求数量远远大于库存数量,只有少部分用户能够秒杀成功。
  • 秒杀业务流程比较简单,一般就是下订单减库存。
  • 秒杀的业务场景跟其他业务场景不一样,主要是秒杀的瞬间,并发非常大,如何针对此大并发是我们需要取解决的。秒杀业务,是典型的短时大量突发访问在瞬间涌入,造成服务器瘫痪,宕机,用户体验差,想必大家都经历过早期春运抢火车票的痛。

秒杀为什么会成为技术难点,系统瓶颈

秒杀与其他业务最大的区别在于,在秒杀的瞬间,系统的并发量和吞吐量会非常大,与此同时,网络的流量也会瞬间变大。会导致访问变慢、商品超卖等问题。

访问慢不需要解释,我们来看看商品超卖现象是怎么产生的
在这里插入图片描述

  • 这个图,其实很清晰了,假设订单系统部署两台机器上,不同的用户都要同时买10台iphone,分别发了一个请求给订单系统。

  • 接着每个订单系统实例都去数据库里查了一下,当前iphone库存是12台。 俩大兄弟一看,乐了,12台库存大于了要买的10台数量啊!

  • 于是乎,每个订单系统实例都发送SQL到数据库里下单,然后扣减了10个库存,其中一个将库存从12台扣减为2台,另外一个将库存从2台扣减为-8台。

  • 现在完了,库存出现了负数!问题来了,没有20台iphone发给两个用户啊!

怎么做

对于系统并发量变大问题

  • 接口限流防刷,限制用户在单位时间内访问接口的频率
  • 这里的核心在于如何在大并发的情况下保证数据库能扛得住压力,因为大并发的瓶颈在于数据库。如果用户的请求直接从前端传到数据库,显然,数据库是无法承受几十万上百万甚至上千万的并发量的。因此,我们能做的只能是减少对数据库的访问。例如,前端发出了100万个请求,通过我们的处理,最终只有10个会访问数据库,这样就会大大提升系统性能。再针对秒杀这种场景,因为秒杀商品的数量是有限的,因此这种做法刚好适用。

怎么解决库存超卖问题?

  • 如果商品数量比较多,比如1万件商品参与秒杀,那么就有1万*10=10万个请求并发去访问数据库,数据库的压力还是会很大,直接读数据库的库存,可能造成超卖。这里就用到了另外一个非常重要的组件:消息队列。我们不是把请求直接去访问数据库,而是先把请求写到消息队列中,做一个缓存,然后再去慢慢的更新数据库。这样做之后,前端用户的请求可能不会立即得到响应是成功还是失败,很可能得到的是一个排队中的返回值,这个时候,需要客户端去服务端轮询,因为我们不能保证一定就秒杀成功了。
  • 这样处理以后,我们的应用是可以很简单的进行分布式横向扩展的,以应对更大的并发。

笔者关于秒杀架构的设计理念

  1. 限流: 鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。(限制用户在单位时间内访问接口的频率)。
  2. 削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。(利用消息队列进行异步处理,流量削峰)。
  3. 异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。当服务端出队,生成订单以后,把用户ID和商品ID写到缓存中,来应对客户端的轮询就可以了。
  4. 内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。(利用redis减少对数据库的访问)。

为什么要这么做:
假如,我们有10W用户同时抢10台手机,服务层并发请求压力至少为10W。

采用消息队列缓存请求:既然服务层知道库存只有10台手机,那完全没有必要把10W个请求都传递到数据库,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。

利用缓存应对读请求:对类似于12306等购票业务和商品秒杀场景,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。

利用缓存应对写请求:缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。
数据库层
数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。

核心代码


    /**
     * 系统初始化时把商品库存加入到缓存中
     */
    @Override
    public void afterPropertiesSet() throws Exception {
   
        //查询库存数量
        List<Map<String, Object>> stockList = miaoshaService.queryAllGoodStock();
        System.out.println("系统初始化:"+stockList);
        if(stockList.size() <= 0){
   
            return;
        }
        for(Map<String, Object> m : stockList) {
   
            //将库存加载到redis中
            redisUtil.getRedisTemplate().opsForValue().set(m.get("goodsId")+"", m.get("goods_stock").toString());
            //添加内存标记
            localOverMap.put(m.get("goodsId").toString(), false);
        }
    }
    /**
     * 请求秒杀,redis+rabbitmq方式
     */
    @SuppressWarnings("unchecked")
    @RequestMapping(value="/go")
    @ResponseBody
    public ResultVo miaosharabbitmq(HttpServletRequest request){
   

        ConcurrentHashMap<String, String> parameterMap = ParameterUtil.getParamet
  • 42
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
基于SpringBoot+SpringMVC,+Mybatis的电商秒杀购物项目源码.zip # 秒杀商城系统设计 ## 1. 产品概述 秒杀是伴随着电子商务流行以来就有的一种营销模式,直白理解就是卖家以限定数,或者限定时间,以极低的价格吸引大的消费者关注,带动店铺整体发展的一种营销手法。由于商品价格低廉,往往一上架就被抢购一空,有时甚至只用几秒钟。 我完整地设计并实现了秒杀商城原型系统,包含三大部分:秒杀商城、商城管理系统和高并发秒杀业务。 ##### 1.1 **秒杀商城** 秒杀商城是是本项目的主要部分,实现了完整的业务流程,包括用户登录、用户注册、商品列表、商品详情浏览、购物车、查看订单、用户下单、秒杀业务等功能。这些功能会在报告的最后展示。 ##### 1.2 **管理系统** 考虑到系统设计的完整性,除了普通用户之外,还应有系统管理员,这里因为我们是B2C的业务,其中B可以认为是使用管理系统的人。其中管理系统包含了管理员注册、管理员登录、创建商品、商品管理(上架或下架)、用户管理(禁用或解禁)、订单管理(是否执行订单)。这些功能会在报告的最后展示。 ##### 1.3 **高并发秒杀业务** 通过对网络吞吐(TPS)进行直观的表现服务器对于并发得性能提升,使用Redis技术、多级Cache缓存技术等技术对后端进行了优化,使得服务器并发处理的性能得到了几倍得性能提升。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值