前言

最近在整理电脑文件的时候,发现了毕业之前看视频学习的在线秒杀系统,现在毕业半年了,正好公司使用了dubbo+zookeeper的分布式框架,合计着整理下之前看过的在线秒杀项目,然后希望能够尽可能地整理成分布式框架(不过希望以后有时间完成吧。。。)。

本文呢,主要是看一下这个秒杀系统主要会涉及哪些问题。其中用到了SpringBoot、Redis、RabbitMQ、MySQL。文章末尾会给出源代码。

正文

其实吧,对于秒杀,在我们的生活中也是很常见的,一有个节日,商家就会搞个秒杀活动促销,我就想起之前的红米k30s至尊纪念版也是抢了好久没抢到。。。

总体来说,我们在这个秒杀过程中买东西的过程与平常购物流程差不多:买东西->抢到了下订单->付款完成订单。但是在这个过程中,因为秒杀活动流量大,请求多,如果活动优惠力度大,几万,几十万都是很有可能的,但是数据库又不可能扛下来这么高的并发。可能活动刚开始数据库就挂了,刚开始就结束了,可能会被消费者直接骂死。

所以为了不get一份鱿鱼套餐,我们的目的就是需要减少服务端对数据库的请求,使得系统稳定运行。我们就来看下设计秒杀系统时会遇到的常见问题。

超卖

如果说服务器崩了,那影响的是购物者的体验。但是如果商品卖超了,那影响的就是money了,尤其是像手机啦,电脑啦之类的电子产品,多卖个几十件,几百件,问题就很大了。所以首先我们就要关注的就是超卖问题。

其实可以先考虑下为啥会超卖呢?

在这个秒杀过程中,因为数据量大,请求多。当请求一窝蜂冲进来之后,数据库中数量已经为0了,但是由于已经有请求放进来了,所以还会去执行sql语句去数据库中进行操作。所以有三种方法可以应付这个问题:

1、sql语句中对库存进行判断,防止为负数时仍执行sqk语句。
2、数据库加唯一索引防止用户重复购买。
3、redis中进行库存预减,请求入队进行排队,实现异步下单。

资源静态化

资源静态化有页面静态化与对象静态化。静态化就是将信息保存到Redis缓存中,当访问的时候可以直接取缓存,而不用每次都去请求服务器。对于服务器来说,也是一件好事。

URL动态化

比如我们打开谷歌浏览器,进入network,我们每点击一个地方,都会出现对应的url,如果拿到这个url,那么就可以在秒杀的时候不断地去请求,这样就很有可能造成什么呢?你的秒杀商品直接被有心人给刷完了。不过我们在秒杀开始之前可以将按钮置灰,这样秒杀前在页面上也拿不到url。

要是开发人员知道这个url,直接自己暗中操作,自己将商品给刷完。比如0.01元抢爱疯12pro,开发人员自己刷个100台,然后辞职跑路。

咳,这样肯定是不道德的,但是为了避免拿到url暗中操作,可以将url进行拼接一个随机字符串,比如md5,uuid之类的都是可以的,只要保证url不是固定的就OK。在秒杀的时候,先对这个url进行判断,通过之后才去进行接下来的操作,这样也提高了一定的安全性。

恶意请求

其实也很正常啊,比如可以以很低的价格在你这里买到还不错的东西啊,那我多搞点服务器,不停的去请求秒杀接口,我拿到之后转手卖掉,不久少工作几个月了么?这么好的事,要我我也干。

当然了,鉴于本人的人品,也是不可能那么做滴,但是我们设计的时候也要防患于未然,安全性同样也很重要。

比如上面提到的动态接口,也是安全性的一种方式。同时我们还可以限制请求的次数,比如5秒内只能请求5次,如果五秒内请求多于五次,请求就会无效并提醒用户。

也可以使用验证码,每次请求都要完成验证码验证后才会发起请求。

限流

限流的话,我们可以从前端、后端两方面来看。

前端:在秒杀开始之前,可以将秒杀按钮置灰,当到达秒杀时间的时候,再将按钮置为正常状态,不然开始之前疯狂点击按钮的话,不就成了活动还没开始就结束了。

后端:如果开始阶段顺利的话,那么就可以进入到下订单,完成订单的操作了,不过我是没在秒杀活动中进行到这一步。。。当数据库中预减库存为0的时候,那么就返回一个秒杀活动结束的标志。

降级:如果流量实在太大的话,也可以在尽量完成秒杀功能的情况下,放弃掉一部分用户来保证系统的可用性。

异步削峰

通过上面的限流操作之后,并不会对所有的请求都完成下单操作。因为肯定存在某个瞬间是有很大流量的请求的,可以将这些请求放入到一个队列中,实现流量削峰,达到流量可控和异步处理。

比如在抢票或者秒杀活动中,因为流量大,不会直接执行所有的请求的,先将请求放到队列中一步一步去消费,不管成功还是失败,都要给前端一个反馈。

分布式Session

为了保证服务的高可用,整个系统会有多个服务,这样就造成了,从别的模块过来了,我怎么知道你的状态呢?我怎么知道你是谁呢?

针对这个问题,我们可以使用uuid作为cookie,并存放到Redis中,在拦截器中队方法进行拦截,通过对方法的拦截,根据cookie来获取对象。在每个页面中,我们可以通过这个key来重新获取对象。

redis的库存如何与数据库的库存保持一致

首先要知道的是,redis中的数量不是库存,我们使用redis就是为了阻挡多余的请求透穿到DB,起到一个保护的作用。请求优先命中redis,缓存中没有再命中数据库。

在并发的情况下,如果想保证一致性,就需要与事务相关,但是redis与数据库是两个数据源,之间是没有事务的。因此使用缓存就会存在一定的不一致。

比如现在有10个商品,如果一万个请求过来,这些请求访问数据库或者访问redis,其实是都一样的,因为最终的目的是将商品数量从10减到0,所以redis将10减到0之后就会返回秒杀结束的信息。所以这两也没有必要非得保持一致。

redis 预减成功,DB扣减库存失败怎么办

其实这个的影响并不是很大,对用户而言,秒杀不成功是很正常的。因为大家都知道这个参与秒杀的分母是很庞大的,秒杀成功也就是个小概率事件。

而且对于商家来说,没有秒杀卖出去还省了一部分费用,对于程序员也不用半夜接电话起床救火。不过在实际中还是要尽量避免这样的情况发生,毕竟秒杀中一次好不容易啊。

单独维护一个秒杀结束标志

1、所有的秒杀相关的接口都要加上活动是否结束的标志,如果结束就直接返回,包括轮寻的接口防止一直轮寻,干脆省事。
2、管理后台也可以手动的更改这个标志,防止出现活动开始以后就没办法结束这种意外的事件。

浏览人数统计

因为我们在项目中已经使用了redis,所以实现人数统计就很简单了。redis有个基本数据类型:String。我们可以维护一个String类型的key,在用户每进入一次页面。让这个key自动+1即可。关于redis五种基本数据类型与三种特殊类型,可以参考下我的这篇:Redis的五种基本数据类型与三种特殊数据类型

总结

其实秒杀的关键呢,还是在于减少数据库的访问。你看前面我们让这个页面静态化、对象静态化、使用缓存、使用队列等等,目的不就是为了减少对数据库的访问么?所以无论再怎么复杂,都是减少DB访问、保证系统高可用为核心滴。

源代码

要运行项目,首先得保证你的redis、rabbitmq都可以正常运行,然后在配置文件中修改对应的配置即可:

然后修改对应的maven仓库、jdk即可。我的jdk用的是当前使用最多的jdk8。将sql文件放到数据库就OK了。
Github地址:
https://github.com/xhXiaoQinDong/miaosha

Java实现在线秒杀系统(主要问题以及源码)相关推荐

  1. 基于Java的在线考试系统(附:源码和课件)

    项目介绍: 本系统是一个基于java的在线考试系统.它的用户由学生.教师和系统管理员组成.学生登陆系统可以进行在线测试和成绩查询.当学生登陆时,系统会随机地为学生选取试题组成考卷.当学生提交考卷后,系 ...

  2. Java毕设项目星光在线光影系统计算机(附源码+系统+数据库+LW)

    Java毕设项目星光在线光影系统计算机(附源码+系统+数据库+LW) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Ec ...

  3. JAVA计算机毕业设计星光在线光影系统计算机(附源码、数据库)

    JAVA计算机毕业设计星光在线光影系统计算机(附源码.数据库) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclis ...

  4. Java毕设项目在线投稿系统计算机(附源码+系统+数据库+LW)

    Java毕设项目在线投稿系统计算机(附源码+系统+数据库+LW) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Ecli ...

  5. Java毕设项目在线招投标系统计算机(附源码+系统+数据库+LW)

    Java毕设项目在线招投标系统计算机(附源码+系统+数据库+LW) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Ecl ...

  6. 计算机毕业设计Java网上图书销售系统演示录像(源码+系统+mysql数据库+Lw文档)

    计算机毕业设计Java网上图书销售系统演示录像(源码+系统+mysql数据库+Lw文档) 计算机毕业设计Java网上图书销售系统演示录像(源码+系统+mysql数据库+Lw文档) 本源码技术栈: 项目 ...

  7. Java毕设项目在线答题系统计算机(附源码+系统+数据库+LW)

    Java毕设项目在线答题系统计算机(附源码+系统+数据库+LW) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Ecli ...

  8. 卡b卡社区在线下单系统无加密全套源码

    介绍: 卡b卡社区在线下单系统无加密全套源码安装说明 把本程序上传到服务器或者主机空间 然后打开域名/install 配置数据库 数据库配置完成后打开域名即可! 后台地址:/admin 账号:2281 ...

  9. 同名在线查询系统微信小程序源码下载支持多种流量主

    这是一款支持查询同名的一款微信小程序 该款小程序支持多种查询模式 重名查询,热度查询,概率查询 有点不好的就是该款小程序的接口好像带了个二维码因为在接口上面所以去不掉 如果不介意的话这款小程序还是很好 ...

最新文章

  1. mysql dba系统学习(10)innodb引擎的redo log日志的原理 mysql dba系统学习(11)管理innodb引擎的redo log日志的一个问题
  2. Flutter一切皆widget但是不要将所有东西放入一个widget
  3. 中点击按钮新建widget_iOS 14-Widget开发
  4. TWRP-recovery中文界面安装方法[转]
  5. 知道接口地址 如何传数据_如何选显示器连接线?四种主流接口要知道
  6. Ajax在IE浏览器会出现中文乱码解决办法
  7. PostgreSQL的 create index concurrently
  8. 《Java并发编程实战》第十章 避免活跃性危急 读书笔记
  9. pandas.tseries.offsets
  10. 未能加载文件或程序集“Newtonsoft.Json”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)
  11. DXUT框架剖析(5)
  12. element 使用阿里图标变形了_2TB不限速的阿里网盘App来了 终于不再忍受众生平等盘...
  13. mysql学生管理系统背景_MySql学习之路1 背景介绍
  14. 资料:《大学英语》精读第三版(全六册)原文及全文翻译
  15. linux配额管理命令,Linux管理员配额管理
  16. linux shell题库,shell习题-30
  17. 对于设计模式中七大原则的理解
  18. 并发控制五(封锁的粒度)
  19. 在Github账户如何修改设置个人头像
  20. 面试题:为什么ConcurrentHashMap的读操作不需要加锁?

热门文章

  1. 编码surface android,【代码】通过 getHolder()方法可以得到这个 SurfaceHolder对象
  2. linux命令大全 tar,linux tar命令详解
  3. java用poi导出wrod文档支持图片并解释代码
  4. win7无损分区和调整合并
  5. 魔术表演的核心秘密(三)——扑克手法是如何利用障眼法的?
  6. 【天草VS黑鹰】动画教程
  7. NoSQL数据库入门与实践答案----第三章
  8. 大头贴计算机教程,如何用电脑摄像头做大头贴
  9. java8 方法或构造函数的引用
  10. 四章——Nginx网站服务(应用——linux防护与群集)