基于SpringBoot的商品秒杀系统

项目框架搭建:
    1.SpringBoot环境搭建
    2.集成Thymeleaf,RespBean
    3.MyBatisPlus
分布式会话:
    1.用户登录
        a.设计数据库
        b.明文密码二次MD5加密
        c.参数校验+全局异常处理
    2.共享Session
        a.SpringSession
        b.Redis
功能开发:
    1.商品列表
    2.商品详情
    3.秒杀
    4.订单详情
系统压测:
        1.JMeter
        2.自定义变量模拟用户
        3.JMeter命令行的使用
        4.正式压测
            a.商品列表
            b.秒杀
页面优化:
    1.页面缓存+URL缓存+对象缓存
    2.页面静态化,前后端分离
    3.静态资源优化
    4.CDN优化
接口优化:
    1.Redis预减库存减少对数据库的访问
    2.内存标记减少Redis的访问
    3.RabbitMQ异步下单
        a.SpringBoot整合RabbitMQ
        b.交换机
安全优化:
    1.秒杀接口地址隐藏
    2.算术验证码
    3.接口防刷  计数器

项目亮点

  • 使⽤分布式Session,可以实现让多台服务器同时可以响应--共享Session

    image-20220512102846957
  • 使⽤redis做缓存提⾼访问速度和并发量,减少数据库压⼒,利⽤内存标记减少redis的访问

  • 使⽤页⾯静态化,加快⽤户访问速度,提⾼QPS,缓存页⾯⾄浏览器,前后端分离降低服务器压⼒

  • 使⽤消息队列完成异步下单,提升⽤户体验,削峰和降流

  • 安全性优化:双重md5密码校验,秒杀接⼝地址的隐藏,接⼝限流防刷,数学公式验证码

优缺点

优势

成本低、系统复杂度低、维护成本低、快速定位问题。符合架构设计的三大原则。

  1. 简单原则:一个系统就可以满足我们秒杀服务的所有动作,没有太多的中间件依赖
  2. 合适原则:在我们的实践项目中,单体系统是最适合不过的了
  3. 演进原则:没有什么系统架构是一出生就定下来的,是随着时间,业务需求,不断演变出来的

劣势

稳定性差、并发量低、扩展性弱

架构

现有

image-20220706174132343

改进

image-20220712120305920

  1. CDN加速:静态资源隔离

    在单体系统中,我们的静态资源(Html,JS,CSS 和 IMG)可能都是通过我们服务端进行返回,存在的问题是:

    • 前端代码维护成本比较高(全栈开发成本也高)
    • 前端代码发布,需要整个系统进行发布
    • 服务器带宽请求资源占用等

    前后端分离的好处:

    • 代码独立维护(低耦合),发布成本低(高效率)
    • 前后端通过接口交互动态数据
    • CDN资源访问加速,减少后端服务压力(高性能
  2. Nginx:反向代理器

    反向代理的作用比较明显, 由于我们服务拆分成多个,那么我们和前端进行交互时,需要提供一个通用的入口。而这个入口,就是我们的反向代理服务器(Nginx)。 例如: 服务域名:https://www.jiuling.com ,根据restful规范,我们可以通过 https://www.jiuling.com/user/1.0/login 将请求转发到 用户服务的登录接口中。

  3. 进程间通信

    随着服务的拆分,在部分功能的实现上,就会涉及到服务间相互调用的情况,例如:订单系统调用商品服务、用户服务等。

    在常见的实现方案上,我们会采用 注册中心RPC框架,来实现这一能力。而我们比较常用的实现方案就是 zookeeper & dubbo

    为什么要使用RPC框架?每个服务提供 RESTful 接口,不是也能够完成服务间通信吗?

    ​ 这里就需要进行对比 RPC 和 RESTful 的区别了:

    • 数据报文小&传输效率快: RPC简化了传输协议中一些必要的头部信息,从而加快了传输效率。
    • 开发成本低:例如 Dubbo框架,封装好了服务间调用的逻辑(如:反射,建连和超时控制等),只需要开发相应的接口和数据模型即可。
    • 服务治理: 在分布式场景下,我们的服务提供者不止一台,那么就涉及到 服务健康,负载均衡和服务流控等情况需要处理,而这部分能力在rpc & 注册中心 的架构下,都已经满足了。

    说完优点后,再来分析一下,RPC的缺点:

    • 耦合性强: 相较于 RESTful而言,RPC 框架在跨语言的场景下实现比较困难。并且版本依赖比较强。服务脱离了当前内网环境后,无法正常提供服务,迁移成本高。
    • 内网调用RPC更适合内网传输,在公网环境下,显得没那么安全。
  4. 分布式微服务

    在上一个版本的服务拆分中, 我们根据不同的业务边界,功能职责,划分出了多个子系统,而针对不同的系统,他所承受的负载压力是不一样的,例如: 订单服务的每个请求处理耗时较长(其他服务压力不大),为了挺升我们的下单量,我们可以只扩容订单服务即可,这就是我们在服务拆分所带来的收益,性能使用率提升! 从上面的图我们可以看到,有些服务出现了不同的重影,每一个方块,可以理解为一台机器,在这个架构中, 为了保证我们的下单成功率,以及下单量,我们主要将服务器集中在了订单服务

  5. 中间件集群部署

    除此之前,再来看看我们的中间件集群部署:

    • mysql 主从架构: 读写分离,减轻主库压力,确保数据能正常写入,保障订单数据落库.
    • zookeeper 主从架构: 保障注册中心可用,避免导致全链路雪崩。
    • redis 哨兵集群: 避免redis宕机导致大流量直接打到数据库中。

改进

高性能

  1. 资源预热——CDN

    资源预热: 通过预先将资源加载到CDN

    回源: CDN找不到资源后,会触发源站(商品服务)调用,进行查询对应资源,如果源站存在该资源,则会返回到CDN中进行缓存。

    OSS: 实际存储静态资源的服务(可参考阿里云OSS)

    CDN的风险

    成本 : 比较直接,就是得多花钱! 带宽 : 在大流量的访问下, CDN 是否能支撑那么多的带宽,每个服务器能支撑的流量是有限的,需要考虑CDN是否能支撑业务的访问量。 CDN命中率: 在CDN命中率低的情况下,比如活动图片,每一个小时都会发生改变,那么每次图片的替换,都会触发回源操作,这时候的资源访问效率反而有所下降。

  2. 缓存预热——redis

    与上面的静态资源加速相对比,动态数据则需要通过缓存进行性能上的优化,老生常谈,为什么redis 那么快?

    • 单线程(redis的性能瓶颈并不在这,所以这个不算优势)

    • 多路I/O复用模型(Epoll)

    • 数据结构简单

    • 基于内存操作

      引入 redis 带来的风险主要有:

      reids 宕机: 单机部署的情况下,会导致大量的服务调用超时,最终引起服务雪崩。可通过哨兵集群优化。 缓存击穿:大流量下,缓存MISS和缓存过期等情况,会导致请求穿透到数据库,如果数据库扛不住压力,会造成服务雪崩。可以通过 布隆过滤器进行优化(解决穿透问题)。 数据一致性: 缓存数据与DB 的数据一致性问题,需要通过更新策略进行保障

  3. 异步调用——MQ

    主要原因在于,通过异步调用的方式,我们将消息投递过去了,就完成了这一次的请求处理,那么性能的瓶颈,由订单服务,转移到了秒杀服务这里。通过减少调用依赖,从而提升了整体服务的吞吐量。

    MQ 带来的常见问题:

    • 数据一致性
    • 重复消费:由于生产者重复投递消息,或者消费缓慢导致重复推送消息。需要通过加锁,消费幂等来保证消费正常。(消费幂:多次请求的结果一样)
    • 消息堆积: 生产能力远大于消费能力情况下,会导致消息堆积。
    • MQ可用性:MQ宕机的情况下,需要支持同步调用切换。

项目流程

  • 登录进⼊商品列表页⾯,静态资源缓存

    • 进入页面时,对LoginVo进行校验(长度,手机号格式)
    • 处理登录信息:获取用户和密码,根据用户查数据库,判断是否存在;用户存在时,MD5校验密码是否正确
    • 登录成功:UUID生成ticket,"user:"+ticket,user存入Redis;将"userTicket",ticket存入Cookie;将ResBean(code,message)返回给前端;前端校验code==200,则跳转到商品详情
  • 点击进⼊商品详情页⾯,静态资源缓存,Ajax获取验证码等动态信息

    商品列表

    • 判断用户是否登录;将user和goodsList(查询数据库所得的秒杀商品信息)返回给model
    • 判断redis中是否有静态页面goodsList,若没有则手动渲染(thymeleafViewResolver),并存入Redis

    商品详情

    • 点击商品列表中某一商品(获得对应的goodsId),前端Ajax跳转到/goods/detail/'+goodsId查询数据库(@PathVariable Long goodsId)获取商品的详细信息
    • 再通过render(detailVo)渲染页面(秒杀时间、图片等信息)
    • render渲染结束调用countDown,countDown根据秒杀状态渲染【秒杀未开始(不断回调countDown)秒杀结束(按钮隐藏等)秒杀进行时(初始化验证码)】
    • 设置验证码,并将验证码的答案存入Redis中【"captcha:"+user.getId()+":"+goodsId,captcha.text()】
  • 点击秒杀, 将验证码结果和商品ID传给后端,如果结果正确。动态⽣成随机串UUID,结合⽤户ID和商品ID存⼊redis,并将path传给前端。前端获取path后,再根据path地址调⽤秒杀服务

    • 点击秒杀按钮:getSeckillPath(),跳转到/seckill/path,获取秒杀地址
    • 验证用户是否登录;根据用户Id,商品Id和输入的验证码,查询Redis验证验证码是否正确
    • 验证通过生成秒杀地址并存入Redis,("seckillPath:"+user.getId()+":"+goodsId,str)其中value:str是UUID+“12345”并进行MD5加密生成的,将Path传给前端
    • 前端调用doSeckill(path)进行秒杀,跳转到'/seckill/'+path+'/doSeckill'调用秒杀服务
  • 服务端获取请求的path参数,去查缓存是否在

    • 在'/seckill/'+path+'/doSeckill'中判断用户是否存在,秒杀地址是否正确;在Redis中根据用户Id和商品ID判断是否重复抢购
    • 查询内存标记(减少对Redis的访问,在服务端代码中设置一个flag标记是否空库存)
  • 如果存在,并且Redis还有库存,预减redis库存,看是否已经⽣成订单,没有的话就将请求⼊消息队列

    • 还有库存,预减库存,预减库存后去判断库存是否<0,若<0,则++;若>0,则进入消息队列

    • 预减库存时,使用分布式锁

      image-20220512175313420

  • 从消息队列中取消息:获取商品ID和⽤户ID,判断数据库库存,然后下单

    • 将用户和商品Id封装成消息发送到消息队列
    • 取消息:根据商品Id查询数据库的库存,再次判断是否重复抢购;下单
  • 下单:减库存,⽣成订单

    • 查询数据库获得秒杀商品的所有信息,减库存,
    • 真正修改库存(减1和判断库存为0在一条语句中,具有原子性,借助InnoDB的行锁)
    • 生成订单
  • 前端轮询订单⽣成结果。50ms继续轮询或者秒杀是否成功和失败

    • 查询数据库是否有订单

项目内容

本项目旨在开发一个基于SpringBoot的商品秒杀系统,实现用户登录、商品列表查看、商品详情查看、秒送、订单详情查看等基本功能,使用JMeter工具对系统接口进行压力测试;并对系统进行页面优化、接口优化和安全优化。

本人任务

  • JMeter自定义变量模拟用户分别在Windows系统和Linux系统进行压力测试
  • 通过页面缓存、URL缓存、对象缓存和页面静态化进行页面优化
  • 通过预减内存内存标记进行接口优化,通过RabbitMQ消息队列进行异步下单
  • 通过隐藏秒杀地址、设置验证码进行安全优化,通过计时器算法实现接口防刷
分布式会话:
    1.用户登录
        a.设计数据库
        b.明文密码二次MD5加密
        c.参数校验+全局异常处理
    2.共享Session
        a.SpringSession
        b.Redis

分布式会话

用户登录

  • 明文密码二次MD5加密 :需要在POM中引入依赖:commons-codec

    inputPass---FormPass--DBPass

       用户端到后端加密:防止密码在网络中进行明文传输  
       存入数据库时再次加密:防止数据库被盗用后 被解密
    数据库存储的是两次加密的结果
    前端传过来的是一次加密的
  • 参数校验

    a.简单的校验 validator组件 通过添加依赖
        @NotNull @Length(min = 6)
    b.对手机号校验:自定义校验组件 hibernate-validator依赖
        IsMobileValidator.java:定义校验规则和组件名结合起来    ValidatorUtil.java 具体的校验  
        @interface IsMobile 组件
    校验时需要在变量名前加上@Value

共享Session--Redis

原理

(26条消息) 4种分布式session解决方案_断橋殘雪的博客-CSDN博客_分布式session

有哪几种共享Session

依赖:spring-session-data-redis

image-20220319202436994 image-20220319202450833

Redis实现分布式Session的两种方式

  • SpringSession

    依赖:
        spring-boot-starter-data-redis
        commons-pool2
        spring-session-data-redis
    添加对Redis的配置
    
    不用动代码 Session会自动保存到Redis上
  • 将Cookie和用户信息存入Redis

    将Session存到Redis
                取消Redis Session依赖   
                配置RedisConfig配置类 注意注释@Configuation @Bean   将key value HashKey HashValue 序列化
                将ticket(UUID)存到Redis  根据Redis中的ticket获取用户信息

Redis的使用

安装  启动   可视化管理器  默认16个DataBase

image-20220319205011416

Redis分布式锁

  setnx key 会出现释放别人的锁  setIfAbsent 只设置了key  加了失效时间
  setnx key value value标记锁看(UUID)但是不是原子性 
  Lua脚本呢可以在Redis服务端写 也可以在Java写  Redis的话网络传输快 但是修改麻烦  Java端相反   将一系列操作变成原子性的

功能开发

功能开发:
    1.商品列表
    2.商品详情
    3.秒杀
    4.订单详情

系统压测

系统压测:
        1.JMeter
        2.自定义变量模拟用户
        3.JMeter命令行的使用:./jmeter.sh -n -t first.jmx -l result.jtl
        4.正式压测
            a.商品列表
            b.秒杀
  • 衡量标准与区别https://www.cnblogs.com/uncleyong/p/11059556.html

    • QPS(每秒的查询率 处理流量多少的标准)

    • TPS:Transactions Per Second,意思是每秒事务数,具体事务的定义,都是人为的,可以一个接口、多个接口、一个业务流程等等。一个事务是指事务内第一个请求发送到接收到最后一个请求的响应的过程,以此来计算使用的时间和完成的事务个数

  • 远程测试

    安装JDK 
    安装MySql
         安装https://blog.csdn.net/Iversonx/article/details/80341596  
         修改密码https://blog.csdn.net/u013277209/article/details/108237466  
         远程连接 https://blog.csdn.net/xdmdth/article/details/52588785  
                https://blog.csdn.net/weixin_47984545/article/details/120620560
    打包 把Jar包放在Linux服务器上 JMeter在Linux系统进行压测  Windows不是真正的服务器 效果不太好
    JMeter也可以在Windows进行压测

image-20220319204437734

image-20220319204647459

image-20220319204458403

image-20220319204518548

image-20220319204749581

image-20220319204550842

image-20220319204619230

页面优化

页面优化:
    1.页面缓存+URL缓存+对象缓存
    2.页面静态化,前后端分离
    3.静态资源优化
    4.CDN优化

页面缓存

Redis做缓存

​ (我们想把整个商品列表页作为页面缓存起来:

​ 步骤:A 从 Redis中读取缓存,若有页面直接返回给浏览器,若没有则手动渲染模板,之前使用的Thymeleaf,然后存到Redis中,并将结果输出到浏览器端:前端 代码中有设置失效时间)

image-20220319205912814

URL缓存

        将不同的id对应的页面也做缓存@RequestMapping("/toDetail/{goodsId}")

image-20220319210020104

对象缓存

​ 缓存用户 (用户是永不失效的,但是若用户信息更改时,若不更新Redis 则会产生数据一致性问题) ​ 解决方法:对数据库有新的操作(更新密码)则删除Redis

延迟双删

页面静态化

即前后端分离

因为使用了Thmeleaf模板,每次浏览器请求的时候 都要从服务器端获取数据然后拼接成模板,渲染返回给浏览器,即使加了缓存,中间传输的是整个模板引擎。我们想前端就是HTML 后端动态的数据才通过服务端传递到前端,前端有很多框架:React、JQuery、zepto...   前端基本不会变动的页面就是静态的,所以要做页面静态化)
      把页面和数据拆分出来 将页面给浏览器缓存起来   没有用前端框架 只是用了Ajax来模拟了一下
      静态资源的优化(css..js,image.)
      商品详情、秒杀、订单详情页面静态化

image-20220319210706415

静态资源优化

(css..js,image.)

解决超卖

1、用户Id+商品Id的唯一索引 解决同一用户秒杀多商品 唯一索引BTree 防止重复购买 事务的原子性:将库存减1和判断库存放在一条语句中 借助了数据库引擎Innonb的行锁 2、修改SQL语句(加库存的判断) 购买商品:判断用户是否登录 库存是否够 是否重复抢购(至此 满足抢购的条件) 开始抢购:事务 判断库存>1 库存-1 利用了数据库本身的行锁

再看看网上的讲解

接口优化

接口优化:
    1.Redis预减库存减少对数据库的访问
    2.内存标记减少Redis的访问
    3.RabbitMQ异步下单
        a.SpringBoot整合RabbitMQ
        b.交换机

页面优化还是要频繁的和数据库交互

比如获取库存

​ ———————所以通过Redis预减缓存,减少和数据库的交互

​ ——————和Redis(在其他服务器上)频繁交互————内存标记

​ 【还可以增强数据库 分库分表】

预减内存

RabbitMQ

 Ubuntu里面安装 并且设置远程访问
  SpringBoot整合 添加依赖 配置 RabbitMQ 、准备一个队列、准备消息队列的生产者消费者

什么是交换机 交换机接受生产者消息并把生产者的消息推向消息队列

交换机的几种模式

Fanout 广播模式  所有消息队列都接受
Direct 直接交换模式 有了RountKey 
    先配置 交换机、消息队列和 RouteKey 
    然后发送消息 使用Direct交换机 指定发送的RouteKey   
    只有匹配的消息队列才能接受
Topic主题模式  
    RouteKey使用通配符描述 *表示一个字段  #表示多个字段  (使用最多)
Headers模式 
    通过不依赖routingkey,使用发送消息时basicProperties对象中的headers匹配队列,headers是一个键值对类型,键值对的值可以是任何类型在队列绑定交换机时用x-match来指定,all代表定义的多个键值对都要满足,any则代表只要满足一个可以了

优化前:四次访问数据库(查库存 查是否重复抢购 生成秒杀订单 生成订单)

Redis优化:将判断重复抢购放在Redis中

预减库存

数据库初始化时把库存存入Redis,秒杀时获取库存,预减库存,
            若不足则返回失败,
            若足够,将请求加入RabbitMQ消息队列,(《--异步--》)并立即返回客户端”排队中“
                  异步操作真正的减库存修改数据库,抢单成功后页面如何显示:客户端页面做一个轮询。

预减内存代码

 //预减库存  redisTemplate.opsForValue()decrement:如果value是一个数值的话 每调用一次就会递减——————原子性的
//Long stock = valueOperations.decrement("seckillGoods:" + goodsId);
Long stock = 
    (Long) redisTemplate.execute(redisScript, 
           Collections.singletonList("seckillGoods:" + goodsId), Collections.EMPTY_LIST);
if (stock < 0){//0-1
    EmptyStockMap.put(goodsId,true);/////////////////////////内存标记
    valueOperations.increment("seckillGoods:" + goodsId);
    return RespBean.error(RespBeanEnum.EMPTY_STOCK);
}

内存标记

why

加入消息队列时(用到了将用户和商品ID 转为JSON )然后发送给交换机  (Topic模式)
 消息队列接收时(真正开始下单 数据库操作),(将JSON转回来:jackson依赖)再次查询库存: 是否重复抢购等
 会出现问题 若库存为10个,用户100000个,那第11个之后的都会访问Redis,所以“”“”“内存标记”“”“

设置了一个Map

​ Map<Long,Boolean> EmptyStockMap = new HashMap<>();//商品ID 是否有库存

​ 系统初始化时 EmptyStockMap.put(goodsVo.getId(),false);false表示还有库存 ​ 当没有库存时 置为true if (stock < 0){//0-1 EmptyStockMap.put(goodsId,true);

客户端的轮询

请求加入消息队列和真正修改数据库存在时间差 所以在客户端显示正在排队中 排队结果(成功则返回订单ID 失败返回-1L 继续等待返回0)轮询查看排队结果

后端 获取秒杀结果

 //这里仍然是用查询数据库 是因虽然Redis中有订单信息 但是若别人退货则无法及时更新到Redis 数据有不一致的情况把?
SeckillOrder seckillOrder = seckillOrderMapper.selectOne(new QueryWrapper<SeckillOrder>()
                .eq("user_id",user.getId()).eq("goods_id",goodsId));
 if (!Objects.equals(seckillOrder,null)){//有订单
     return seckillOrder.getOrderId();
}else if(redisTemplate.hasKey("isStockEmpty:"+goodsId)){//有这个key说明 已经没有库存了-OrderServiceImpl.java
    return -1L;
}else {//没有对应订单 还有库存 则排队
    return 0L;
}

前端 轮询

image-20220319212550261

安全优化

安全优化:
    1.秒杀接口地址隐藏
    2.算术验证码
    3.接口防刷  计数器

秒杀接口地址隐藏

获取秒杀地址 并存入Redis

public String createPath(User user, Long goodsId) {
     String str = MD5Util.md5(UUIDUtil.uuid()+"123456");
     redisTemplate.opsForValue().set("seckillPath:"+user.getId()+":"+goodsId,str,60, TimeUnit.SECONDS);
     return str;
}

校验秒杀地址

public Boolean checkPath(User user, Long goodsId,String path) {
   if (user == null || StringUtils.isEmpty(path)){
      return false;
    }
   String redisPath = (String) redisTemplate.opsForValue().get("seckillPath:"+user.getId()+":"+goodsId);
    return path.equals(redisPath);
}

image-20220319213154146

验证码

  • 防止黄牛脚本(会计算 之类的)

  • 减缓 短时间内大量的请求

    从Gitee上下载的 注意看使用方法

接口防刷

三种算法

计数器算法 (redis的自增 原子性的) 
            这里限制了规定时间内访问次数 但是会出现 在规定时间的某段时间频繁访问 另一段时间空闲  临界问题和资源浪费
漏桶算法(保护他人)   
水龙头的 水表示请求 放在水箱中  水箱有一个漏斗来过滤请求 水太大: 可能会造成水箱装满 (把服务器撑爆) 使用队列 
            洞太大:出水量过的大 水太少 资源浪费 
令牌桶算法(保护自己)  
    有以恒定速度专门生成令牌的机制,生成时会判断令牌桶是否满了,没有满则生成放进桶, 桶里面装着令牌   
    请求过来会请求令牌 请求成功 则执行业务逻辑,如果令牌桶里面的令牌用完了 还是以恒定的速度生成令牌
        +++++++++++++能够应对突然的大量请求

基于SSM的水果商城系统

项目内容

本项目旨在开发一个基于 SSM 框架的水果商城系统, 系统支持两种角色:管理员和普通用户。管理员拥有查询水果购买统计表信息、水果类目管理、用户管理、商品管理、订单管理、公告管理和留言管理等权限;普通用户拥有注册登录并修改个人信息的权限,可以查询并收藏商品、加入购物车、结算、查看物流状态等

本人工作

  • 用户登录时对密码进行二次MD5加密;并通过自定义validator组件对用户手机号进行校验
  • 搭建Spring+SpringMVC+Mybatis框架,前端集成Themeleaf模板引擎
  • 通过Redis实现分布式Session解决分布式会话问题,Redis Desktop Manage远程连接Redis并查看Redis缓存
  • 使用 pagehelper 插件实现分页;使用 UEditor富文本编辑器实现图文信息添加;使用 ECharts 可视化图表库实现统计表设计

用到的注解

@Valid:搭配校验组件一起使用 表示对这个变量进行校验
@RestController注解相当于@ResponseBody + @Controller合在一起的作用

要了解的

  • Cookie

遇到的问题

超卖

下载一些软件时 用到外国的源 更换国内源

会问的问题

项目-SpringBoot

  1. 使用JMeter自定义变量模拟批量用户,并分别在Windows系统和Linux系统进行压力测试
  • 怎么自定义变量?

    • 新建线程组:设置线程属性:线程数、循环次数等
    image-20220321103634417
    • 添加HTTP请求默认值: 协议选择HTTP 服务器选择本地 localhost 端口号选择8080
    image-20220321110124649
    • 添加CSV 数据文件设置:Comma-Separated Values,CSV,有时也称为字符分隔值

    ​ 选择文件;设置文件编码;设置变量名(变量名使用逗号间隔);设置分隔符等

    image-20220321110512189
    • 添加HTTP Cookie管理器:添加 存储在Cookie管理器中的Cookie(名称与程序对应,值与CSV文件对应,域选择localhost)
    image-20220321110818796
    • 添加HTTP请求:选择HTTP请求(GET 或 POST) 选择测试的路径 可以添加路径的参数(名称和值)
    image-20220321111151031
    • 添加监听器:可以选择聚合报告、查看结果树等
  • 压力测试结果怎么样?

    压力测试结果首先是与计算机性能有很大关系的;其实就是跟系统本身的性能有关,因此我也做了一些性能优化:页面优化、接口优化等,主要是减少对数据库和Redis的访问,因为发现涉及到数据库的修改时,QPS就比较小。

    衡量标准与区别https://www.cnblogs.com/uncleyong/p/11059556.html

    • QPS(每秒的查询率 处理流量多少的标准)每秒查询率,是一台服务器每秒能够响应的查询次数(数据库中的每秒执行查询sql的次数),显然,这个不够全面,不能描述增删改,所以,不建议用qps来作为系统性能指标。

    • TPS:Transactions Per Second,意思是每秒事务数,具体事务的定义,都是人为的,可以一个接口、多个接口、一个业务流程等等。一个事务是指事务内第一个请求发送到接收到最后一个请求的响应的过程,以此来计算使用的时间和完成的事务个数

      以单接口定义为事务为例,每个事务包括了如下3个过程:

        a.向服务器发请求

        b.服务器自己的内部处理(包含应用服务器、数据库服务器等)

        c.服务器返回结果给客户端

        如果每秒能够完成N次这三个过程,tps就是N;

      如果多个接口定义为一个事务,那么,会重复执行abc,完成一次这几个请求,算做一个tps。

      如果是对一个查询接口(单场景)压测,且这个接口内部不会再去请求其它接口,那么tps=qps,否则,tps≠qps

      如果是容量场景,假设n个接口都是查询接口,且这个接口内部不会再去请求其它接口,qps=n*tps

  • 为什么要在两个系统做压力测试?

    Windows系统和 真正的Linux服务器还是有很大区别的

  • 在Linux系统测试需要什么?

    项目可以在Linux系统运行:MySql+JDK+Redis(在其他系统上)+JMeter

    JMeter命令行的使用:./jmeter.sh -n -t first.jmx -l result.jtl first.jmx是JMeter的一些配置

  1. 通过Redis实现分布式Session解决分布式会话问题,执行Lua脚本实现分布式锁
  • 分布式会话问题具体指什么?

还有哪些解决分布式会话的方案?

在Redis还是Java端编写Lua脚本,各有什么优缺点

分布式锁有哪几种?

为什么要使用Lua脚本

通过页面缓存、URL缓存、对象缓存和页面静态化进行页面优化,其中缓存使用Redis实现

页面缓存指什么?

URL缓存指什么?

对象缓存 指什么?

如何进行页面静态化?

为什么要进行页面优化?

通过预减内存内存标记等进行接口优化,通过RabbitMQ消息队列实现异步下单功能

如何预减内存?为什么要

如何进行内存标记?为什么要

减少访问Redis

RabbitMQ有哪几种模式?有哪几种引擎?

如何进行异步下单?

通过隐藏秒杀地址、设置计算验证码进行安全优化,通过计时器算法实现接口防刷功能

如何隐藏秒杀地址?为什么要隐藏

为什么要设置验证码?

接口防刷具体指什么?为什么要接口防刷?

除了计时器算法,还有什么算法?优缺点 【高并发】

这个项目遇到了什么问题 怎么解决的 收获了什么

项目-SSM

  1. 搭建Spring+SpringMVC+Mybatis框架,前端集成Themeleaf模板引擎

    关于SSM框架的基本知识

  2. 用户登录时对密码进行二次MD5加密;并通过自定义validator组件对用户手机号进行校验

    为什么要进行二次加密,还有什么加密算法

    如何自定义组件

  3. 这个项目遇到了什么问题 怎么解决的 收获了什么

项目-科研

1、简单描述一下你的科研项目

2、科研中遇到的困难 如何解决的

个人技能

  1. Java基础知识
  2. 为什么使用C++作为科研项目开发语言
  3. MySql事务有哪些特性。。
  4. Redis的特性 基础知识
  5. 计算机网络
  6. 项目中用到Maven管理项目,具体有哪些
  7. 英文的自我介绍