秒杀P7-项目部署与压测

147 阅读6分钟

spring如何支持事务

@Transactional注解:加在方法上,表示方法受事务保护

不加参数:表示默认隔离级别,repeatable read

@Transactional
public Order createOrder(int userId, int itemId, int amount, Integer promotionId) {
    // 校验参数
    if (amount < 1 || (promotionId != null && promotionId.intValue() <= 0)) {
        throw new BusinessException(PARAMETER_ERROR, "指定的参数不合法!");
    }

加参数:影响事务传播机制

  • @Transactional(propagation = Propagation.REQUIRED)默认参数,可以不写。当前方法中没有启用事务,就生成事务事务。如果已经有事务(比如此处嵌套事务,外部方法有事务,还调用了该方法),就不做处理。

  • @Transactional(propagation = Propagation.REQUIRES_NEW):不管当前方法是不否在事务内,该方法都是个独立事务。

    • 因为要generateOrderID()方法是独立的,希望id永远是递增的,即使createOrder方法失败,浪费一个id,id也不回滚
    • 加注解,generateOrderID()方法受事务保护。方法开始自动给定事务,结束时,自动commit提交,中间抛异常自动回滚。底层是基于AOP实现。
@Transactional(propagation = Propagation.REQUIRES_NEW)
private String generateOrderID() {
    StringBuilder sb = new StringBuilder();

    // 拼入日期
    sb.append(Toolbox.format(new Date(), "yyyyMMdd"));

    // 获取流水号
    SerialNumber serial = serialNumberMapper.selectByPrimaryKey("order_serial");
    Integer value = serial.getValue();

    // 更新流水号
    serial.setValue(value + serial.getStep());
    serialNumberMapper.updateByPrimaryKey(serial);

    // 拼入流水号
    String prefix = "000000000000".substring(value.toString().length());
    sb.append(prefix).append(value);

    return sb.toString();
}
  • 创建流水号的方法serialNumberMapper.selectByPrimaryKey("order_serial"),根据主键查询流水【读】。方法的sql结尾加了for updateX锁

  • generateOrderID()方法的事务a,读到这一行的时候,如果不加for update,有可能已经有别的事务b在改数据,加了X锁。此时基于MVCC原理,a不读正在改的数据,a读的是历史版本数据。但应该是读b更新完后的数据。

  • 所以加for update【X锁】,与已经在改的b事务X锁互斥,等事务b改完之后,才轮到a。

  • 强制事务不去读历史版本数据

select name, value, step
from serial_number
where name = #{name,jdbcType=VARCHAR} for update

云端部署

重点:项目——创建流水、云端部署、压测。原理——spring事务。

服务器部署Nginx,部署前端代码,配置反向代理,还有tomcat的秒杀代码

QQ浏览器截图20230618152214.png

需要修改配置

  • 配置test配置文件
  • 把jdbc的MySQL公网ip改成本地ip,mysql和tomca都在云服务器上,本机就能访问
  • 允许跨域的ip,改成公网ip

image.png

修改配置test环境log的xml文件 配置日志在服务器的存储路径

image.png

⭐项目代码用meaven打jar包,传到服务器上

——————环境变量path配置jdk的bin目录。(给meaven用)

  • springboot的meaven插件,双击运行packang可以顺序执行等等测试+打包。
  • test测试代码逻辑有数据处理的流程,复杂,手动敲命令跳过
  • mvn clean package -Dmaven.test.skip=true。清理target,打包,跳过测试代码。回车运行
  • cd target。查看jar包是否打包成功
  • scp seckill-0.0.1-SNAPSHOT.jar root@服务器IP:/root把包传到服务器。要输入密码

image.png

image.png

image.png

image.png

服务器上运行jar包,需要安装jdk

  • yum list java*显示安装包。
  • yum install -y java-1.8.0-openjdk.aarch64。安装
  • java version 查看安装是否完成

image.png

image.png

  • 后台启动jar,本地编写sh脚本启动,传到服务器上
  • nohup表示运行过程中出现日志信息,存到文件中不打印到控制台
  • &”结尾,表示后台启动。链接的客户端关了,仍在后台运行
  • java -jar xxx.jar表示启动xxxjar包文件
  • --spring.profiles.active=test,指定配置文件的参数,运行test环境的配置文件
  • -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m,声明jvm内存空间大小。JVM最小最大分配1G内存,新生代0.5G
  • 查询seckill服务的端口,杀。每次启动是先杀掉现有旧的,在启动新的。
    • pid=ps aux | grep seckill | grep -v grep | awk '{print $2}'
    • kill -9 $pid
  • scp startup. sh root@服务器IP:/root。上传脚本到服务器,要输入服务器密码

image.png

image.png

安装Nginx

  • yum list nginx*看包
  • yum install -y nginx.aarch64安装

先启动tomcat再配置nginx

  • 有JDK以后就能启动了
  • 设置权限
  • 启动启动文件
  • 尝试访问tomcat。tomcat默认路径是8080端口。访问IP:8080
  • 可以访问,配置完成

image.png

image.png

image.png

tomcat配置好了,没有前端代码访问麻烦。

把前端代码装到nginx中

  • nginx -c /etc/nginx/nginx.conf 启动Nginx,指定配置文件
  • 浏览器访问服务器IP,会看到Nginx默认页面
  • 把本地前端代码压缩发到Nginx的前端访问文件夹中
  • 本地压缩包路径下,打开cmd命令框,scp seckill-site.zip root@服务器IP:/usr/share/nginx/html
  • unzip seckill-site.zip解压,得到seckill-site文件夹【蓝色】
  • 修改参数。
    • cd seckill-sitecd jsvim common.js 修改seckill-site/js目录下的common.js
    • 修改服务器路径。把本机IP改成服务器IP:90

image.png

image.png

配置Nginx

  • cd etc/nginxvim nginx.cong。修改配置
  • 需要两个虚拟server
    • 一个监听80端口,代理web服务
    • 一个监听90端口,代理后端代码
  • 注释掉原有server部分
  • 代理前端
    • 监听80端口
    • location / 访问路径是根路径。没有后缀,直接访问80端口。
    • alias 分发,代替根路径。
    • index 设施首页。访问80端口时,默认访问的页面。
  • 负载均衡
    • 监听90
    • server_name声明服务器名,防止重复,取为“_”下划线
    • 路径是根路径
    • proxy_pass http://myserver;负载均衡,分发给其他服务器组。分发传给myserver处理。
    • myserver是自己配置的服务器组。多个服务器会均匀分发
  • 配置服务器组
    • upstream 配置
    • 配置本机虚拟server组地址。
    • 超过三次访问失败就不访问(认为服务器组挂了?)。超过30s访问不到就认为访问失败,不再访问。
    • :wq保存退出文本编辑模式
  • 重启Nginx。nginx -s reload

image.png

  • 后台启动jar,本地编写sh脚本启动,传到服务器上
  • nohup表示运行过程中出现日志信息,存到文件中不打印到控制台
  • &”结尾,表示后台启动。链接的客户端关了,仍在后台运行
  • java -jar xxx.jar表示启动xxxjar包文件
  • --spring.profiles.active=test,指定配置文件的参数,运行test环境的配置文件
  • -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m,声明jvm内存空间大小。JVM最小最大分配1G内存,新生代0.5G
  • 查询seckill服务的端口,杀。每次启动是先杀掉现有旧的,在启动新的。
    • pid=ps aux | grep seckill | grep -v grep | awk '{print $2}'
    • kill -9 $pid
  • scp startup. sh root@服务器IP:/root。上传脚本到服务器,要输入服务器密码

image.png

image.png

安装jmeter,配置path变量。

cmd命令行,敲Jmeter打开软件

压测设置

  • 创建线程组。50线程,10秒内,循环10次
  • 创建取样器,http请求。设置参数。
    • 指定协议、服务器IP、端口号90【因为监听后端】、请求类型、压测路径、编码格式

image.png

  • 添加监听器-查看结果树
  • 添加监听器聚合报告。样本:线程数、吞吐量:每秒处理请求数
  • 保存

image.png

image.png

压测前先查看服务器状态

  • top -H,查看界面
  • load average系统负载,即任务队列的平均长度。三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。2核CPU要在2以下。
  • us用户空间占CPU的百分比。在100%以下
  • MySQL靠前,后面要降低占用的百分比

top命令及参数

原文链接:blog.csdn.net/langzi6/art…

带宽是瓶颈 压测商品界面:get请求,50/10/10 mysql,nginx都占用14% 吞吐量:43-74

新建测试组,http请求中,添加三个参数

image.png

image.png

添加配置元件-HTTP cookie管理器

image.png

配置cookie参数

image.png

压测“创建订单”:post请求。300/10/10 mysql占用14% 吞吐量300,因为库存少,后面都直接失败

可参考 原文链接:blog.csdn.net/qq_43950000…

怎么部署

MySQL分布式部署

读写分离