Java秒杀系统优化-Redis缓存-分布式session-RabbitMQ异步下单-页面静态化

项目介绍

基于SpringBoot+Mybatis搭建的秒杀系统,并且针对高并发场景进行了优化,保证线程安全的同时极大地提高了服务器的吞吐量,主要优化手段有页面静态化、Redis缓存(页面缓存、对象缓存)、RabbitMQ异步下单,项目实现的主要功能为 登录-->商品列表浏览-->秒杀-->付款或返回。本项目利用压测工具Jmeter对优化前后的性能做了详细的评测,附带完整的测试报告以及整个系统的设计思路报告。

软件说明

整个项目的结构为严格的Maven项目结构,源码包下的包名即为其主要作用的缩写名,易于理解,概不赘述。

本文重点阐述计思路及优化方案,并附在Jmeter下压测的完整结果报告。

设计方案

以下分功能模块阐述:

一、登录功能及session

登录的设计并不复杂,主要思路为两次MD5+盐化,首先为前端用固定salt+password做一次MD5然后传至后端,后端逻辑首先对用户存在与否做判断,然后取出该用户的salt值,和前端传来的已经一次MD5的password再次MD5,然后比较即可,然后生成session并存储在redis缓存中,返回cookie。值得注意的是在user表中加入随机的salt可极大降低彩虹表攻击的风险,还有就是将session值存储于redis缓存中也极大地降低了对数据库的访问。

二、商品列表、订单详情、商品详情功能

这部分功能逻辑十分简单,即为查数据,然后展示,无须赘述,需注意的是,这部分功能的优化策略,详见后文。

三、秒杀功能

该功能为系统的核心功能,既要保证程序的线程安全性,又要满足高并发场景的需求。

在未优化前,其主要的逻辑为:查库存-->查是否秒杀-->秒杀,又因为该逻辑理论上应为一个原子的操作,所以加锁,或者作为事务,但是这样会大大影响程序的并发性能,所以需做优化。

四、数据库

数据库的主要设计为五张表:goods、miaosha_goods、miaosha_user、miaosha_order、order_info

具体数据表的主要结构,在./sql/中有sql文件,并且./java/util/中有用于生成测试用户的脚本,有兴趣的读者可以查看。

以上即为主要功能,接下来阐述对应的一些优化手段。

优化方案

一、页面缓存

页面缓存的主要思路为,将一些用户经常请求的页面,例如/goods/to_list--商品列表页面,存储到redis缓存中,在用户请求的时候直接在缓存中获取并返回,如果取缓存失败,则利用thymeleaf的手动渲染,渲染后存入缓存,并且返回。我们可以很明显的知道,不使用页面缓存的请求,每次都先访问数据库,然后经thymeleaf渲染,然后返回,其中渲染的过程可能需要从磁盘中读取html模板,而使用页面缓存以后,直接在内存缓存中读取,无需查库和渲染,只有失效的情况下才需要查库渲染,所以在些用户经常请求的页面中使用页面缓存优化,可大大降低对数据库和服务器的压力。(需要注意的是合理的设置页面缓存的有效期)。

二、对象缓存

相对于页面缓存,对象缓存是个更细粒度的缓存,比如说在登录模块中的session中,我们把session对应的user对象存储到redis缓存中,那么在需要user对象的页面中,既不需要登录,也不需要更具cookie去查找数据库,只需要通过cookie在redis中获取user对象,即可使用,同理,这样类型的缓存也会减小对数据库的压力。

三、页面静态化

上述的两种缓存,都是利用redis缓存服务器来实现的,虽然可以降低对数据库和服务器的压力,但是,redis服务器的容量和处理能力也是有限的,所以我们可以考虑将页面模板直接缓存到用户的浏览器,那么每次请求用户只需要请求用于渲染的对象即可,这不仅仅减轻了redis服务器的压力,同时也减少了带宽的消耗,此即为页面静态化。

在本项目中,主要实现的是商品详情、订单详情页面、秒杀页面的静态化,主要方法是利用ajax的异步加载,请求渲染需要的对象,并且通过配置

####### spring.resources的相关参数来告诉浏览器是否缓存,缓存有效时间等等。

四、静态资源优化

主要手段包括JS/CSS压缩,CDN等,此项目中并没有尝试,但不失为优化的另外一些好的思路。

以上部分的优化手段主要为缓存、页面优化等于前端比较接近的手段,对于后端接口的优化将在以下部分阐述

五、接口优化

主要思路为Redis预减库存+RabbitMQ异步下单

具体流程如下:

1、系统初始化,加载库存到redis缓存

2、收到请求,预减库存

3、判断库存,若剩余,则入队列,否则秒杀失败

4、出队下单

分析:

一、通过将库存加载到redis中,使得每次判断、减少库存直接从内存中读取,无需访问数据库

二、收到请求预见库存,然后判断

注意这一顺序非常重要,保证了线程安全

分析:因为redis封装的decr()等函数是线程安全的,无需外加同步,所以你通过decr()减少库存后获取到的库存永远都是你刚刚减少后得到的库存,本身就是个原子操作,不会存在线程安全问题,然后根据这个库存来入队,不符合条件的秒杀请求直接返回失败,极大地减少了服务器的压力,而且整个后台逻辑中,需要保证原子性的也仅仅是decr()这一个操作,并且由于redis经过了乐观锁优化,所以整个系统的并发性相对于自己首先同步代码而言,并发性得到了极大的提高。

三、完成了上述的操作,再去实现接下来的逻辑就很简单了,唯一需要注意的是,从队列中出来的请求执行秒杀过程是一个事务,需完整执行,否则回滚。

同时,订单的详情页面做一个静态化优化,前端轮询秒杀结果,得到结果后进行渲染即可。

以上即为接口优化的阐述,接下来是压测报告。

测试参数

服务器:(Mysq、Redis、RabbitMQ等服务也均安装在本机上

CPU: Hasse/战神Z7m Intel-i7-6700HQ 2.6GHz-3.5Ghz 四核心八线程 三级cache 6M

内存: 8G DDR3L

磁盘: 5400转/s 1TB

Java版本:1.8.0_161 Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

MySQL:5.7.20-log MySQL Community Server (GPL)

Redis:4.0.10 容量--100M

RabbitMQ:3.7.7

Mybatis、Druid等具体配置参数见./resource/application.properties文件

测试方法

测试工具使用Jmeter并发测试工具,为保证无非相关变量的影响,每次测试的并发线程数均设为1000,并发时间1s,并发循环次数为10次,如图所示:

/goods/to_list接口测试

该接口为商品列表接口,对该接口做了页面缓存的优化,分别对优化前,优化后做压测,结果如下:

优化前的测试结果

优化后的测试结果

对于上图的两个测试,我们比较关注的是聚合报告里的 ThoughPut 的值,其值可以作为吞吐量的一个较好估计。

由图可见:

优化前,系统吞吐量为:921.1/sec

优化后,系统吞吐量为:4046.9/sec

也就意味着,加速比为:4.39。

/goods/detail/{goodsId}接口测试

该接口为商品详情接口,对该接口实现了页面静态化的处理,分别对优化前,优化后做压测,结果如下:

优化前的测试结果

优化后的测试结果

对比以上两图,会发现,似乎区别并不明显,很容易让人得出优化无效的结论,其实不然

据本人分析,这种情况应该是由Jmeter自身导致的,因为Jmeter做测试的时候并不会依赖于其他浏览器,只是发起http请求,而浏览器所具备的一些功能,他并没有,比如,缓存,所有,利用Jmeter进行测试并不能得出一个如意的结果,但是,我们可以通过浏览器来大致的了解页面静态化后的一些改变。如图:

可以清楚的看到,这个页面大部分的内容都被“已缓存”,只有400个字节左右的对象被请求并传输,这也就达到了我们优化前的目的了。

秒杀接口优化

对于接口测试,我实现准备了1000个user和cookie,具体脚本见./java/util/下代码,在Jmeter中使用参数方法可自行百度,如图:

对于秒杀接口,我们只对优化后的接口进行压测,测试的情况分为两类:

1、秒杀库存充足

2、秒杀库存不足

对于秒杀库存充足的情况,我们设置初始的库存为200,然后,并发量和其他测试设置一致,结果如图:

对于秒杀库存不足的情况,我们设置初始的库存为0,然后,并发量和其他测试设置一致,结果如图:

对于处理逻辑比较复杂的接口而言,最好和最坏的情况能达到这样的一个吞吐量,同时保证线程安全性,比较满意。

以上为全部测试报告,读者若有不明之处,欢迎提问。

MySQL建表添加乐观锁字段_Java秒杀系统优化-Redis缓存-分布式session-RabbitMQ异步下单-页面静态化...相关推荐

  1. mySQL建表允许最多多少字段?

    遇到新建一个很多列的表,200多列,大部分是VCHAR,建表失败,说每行允许最多4096字节长度,超过了最大长度. 百度查询了一下,mySQL对列限制比较宽松,好像最多允许1024个列.但是每行记录的 ...

  2. MySQL数据库建表时对于某个字段设置了默认值,但是使用Spring Data Jpa的save后默认值没有生效

    问题描述:MySQL数据库建表时对于某个字段设置了默认值,但是使用Spring Data Jpa的save后默认值没有生效.MySQL数据库中构建的用户表表结构如下所示: DROP TABLE IF ...

  3. MySQL建表(那些字段必须)命令详解

    MySQL建表(那些字段必须)命令详解1. create table命令 强调:使用建表命令之前必须使用use命令选择表所在的数据库.create table命令的格式如下: create table ...

  4. MySQL 修改表 添加字段

    MySQL 修改表 添加字段 ALTER TABLE 表名 ADD COLUMN 添加的字段 VARCHAR(10) NOT NULL COMMENT '备注' AFTER 某个字段;

  5. mysql 建表最佳实践

    目录 一 自增主键 id 二 创建时间.更新时间 三 字段添加索引 四 数据逻辑删除 五 灵活运用数据库编码 六 添加 version 字段 七 COLLATE 区分字符大小写 本文主要总结工作这些年 ...

  6. 总结MySQL建表、查询优化实用小技巧

    MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些实用小技巧. 技巧一.数据表冗余记录添加时间与 ...

  7. mysql建表测试_总结MySQL建表、查询优化实用小技巧

    MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些实用小技巧. 技巧一.数据表冗余记录添加时间与 ...

  8. mysql建表是要注意什么问题_MySQL建表注意事项

    1.建表规范 -- 数据库名丶表名,全部使用小写字母,使用"_"下划线连接且长度小于12,做到见名知意 2.建议使用 innodb 引擎,这也是MySQL的默认引擎 3.字段类型选 ...

  9. phpstudy mysql建表_MySQL_总结MySQL建表、查询优化的一些实用小技巧,MySQL建表阶段是非常重要的一 - phpStudy...

    总结MySQL建表.查询优化的一些实用小技巧 MySQL建表阶段是非常重要的一个环节,表结构的好坏.优劣直接影响着后续的管理维护,赶在明天上班前分享总结个人MySQL建表.MySQL查询优化积累的一些 ...

最新文章

  1. android获取string.xml的值(转)
  2. 粤桂协作消费对接活动 农业大健康·李喜贵:功能性农业合作研究
  3. php cgi远程控制,php-cgi如何使用(php cli模式执行php文件)
  4. drop table中cascade的含义及用法
  5. 《Cracking the Coding Interview》——第11章:排序和搜索——题目7
  6. 旧文重发:苹果是怎么吃到的?
  7. pthread_cleanup_push()/pthread_cleanup_pop()
  8. curl post file PHP
  9. Linux之ssh-add命令
  10. 181113每日一句
  11. w ndows7如何清理垃圾,Win7系统清理:如何清理Win7系统盘垃圾
  12. Android手机打开开发者模式调试App
  13. centos8同步时间安装时间校准服务
  14. 你和你的女神之间,差了一个OpenCV口红色号识别器
  15. 项目管理中的进度控制与目标计划
  16. win10(家庭版)打开本地组策略失败的处理方法
  17. CAD数据导入数据库
  18. ssm美食论坛系统毕业设计源码191023
  19. VBA-EXCEL统计数据
  20. 华擎主板设置来电开机_华擎主板设置来电开机_一块性价比超高的B550主板、华擎(ASRock)B550 Extreme4极限玩家主板 评测......

热门文章

  1. 通过SQL即可让监控分析更简单更高效
  2. 真香!8 行代码搞定最大子数组和问题
  3. 服务器之后加码存储,浪潮信息重磅发布新一代 G6 存储平台
  4. 用友BIP|YonBuilder+APICloud 双平台,“1+1>N”的低代码战略
  5. CSDN 独家对话阿里云贾扬清、华先胜等大咖,剧透阿里云原生技术密码
  6. Java 最高均薪 19015 元! 8 月程序员工资出炉,你拖后腿了吗?
  7. 移动云2020 H1营收44.57亿元,同比增长556.4%
  8. Kafka精华问答 | kafka节点之间如何备份?
  9. python交叉编译的配置 脚本怎么写_如何写一个简单的脚本并配置
  10. 重装linux之后gcc等下载不了,Redhat linux下安装gcc