当前位置: 首页 > article >正文

【商城实战(24)】商城性能大揭秘:压力测试与性能监控实战

【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配,乃至运营推广策略,102 章内容层层递进。无论是想深入钻研技术细节,还是探寻商城运营之道,本专栏都能提供从 0 到 1 的系统讲解,助力你打造独具竞争力的电商平台,开启电商实战之旅。

目录

  • 一、压力测试工具选择与计划制定
    • 1.1 JMeter 工具介绍
    • 1.2 制定压力测试计划
    • 1.3 源码实现
  • 二、执行压力测试与性能指标收集
    • 2.1 模拟高并发场景
    • 2.2 收集系统性能指标
    • 2.3 源码实现
  • 三、搭建性能监控系统
    • 3.1 Prometheus + Grafana 介绍
    • 3.2 搭建过程
    • 3.3 关联监控指标端点
    • 3.4 源码实现
  • 四、总结与展望


一、压力测试工具选择与计划制定

1.1 JMeter 工具介绍

JMeter 是一款由 Apache 软件基金会开发的基于 Java 的开源测试工具,最初主要用于 Web 应用程序测试,如今其应用范围已大幅拓展,可对各类网络服务进行全面性能测试,堪称虚拟的 “压力制造机”。

它具备诸多显著优势。在协议支持方面,JMeter 功能强大,能处理 HTTP、HTTPS、FTP、SMTP、POP3 等常见网络协议,以及 JDBC(用于数据库测试)、JMS(Java 消息服务)等企业级应用相关协议,这使得它能适应各种通信协议的软件系统测试需求。

从测试场景设置来看,JMeter 十分灵活。通过线程组,可轻松定义模拟用户数量、启动方式(同时启动或逐步启动)以及操作循环次数;逻辑控制器则允许根据不同条件和逻辑组织测试步骤,比如设置循环执行某些操作,或依据特定条件决定是否执行某个请求,借此能够模拟出极为真实的用户行为和业务场景。

测试结果分析环节,JMeter 同样表现出色。它提供多种监听器,聚合报告可展示每个请求的平均响应时间、最小响应时间、最大响应时间、吞吐量以及错误率等关键指标;图形结果监听器以图表形式展示响应时间随时间的变化趋势,让我们能直观地洞察系统性能的波动情况,助力快速定位系统性能瓶颈,找出问题所在。此外,对于不太熟悉脚本编写的测试人员,JMeter 的录制与回放功能也非常实用,通过代理服务器可录制浏览器中的用户操作,并自动转换为测试脚本,在此基础上还能进一步优化完善,极大提高了测试脚本的编写效率。

1.2 制定压力测试计划

  • 测试目标:明确本次压力测试旨在评估商城系统在高并发场景下的性能表现,重点关注系统的响应时间、吞吐量、错误率等指标,以确定系统是否能够满足预期的业务负载需求,找出系统可能存在的性能瓶颈。
  • 测试范围:涵盖商城的核心业务接口,如商品查询、用户登录、添加购物车、下单等功能接口,确保这些关键业务在高并发情况下的稳定性和可靠性。
  • 场景设计
    • 场景一:商品查询:模拟大量用户同时查询商品列表,逐渐增加并发用户数,观察系统性能变化。
    • 场景二:用户登录:设置不同的并发用户数,模拟用户集中登录的场景,测试登录功能的响应速度和系统承载能力。
    • 场景三:下单操作:模拟多个用户同时下单,检查订单生成的准确性和系统的处理能力,关注库存扣减等相关业务逻辑是否正确执行。
  • 数据准备:准备大量的测试数据,包括商品信息、用户信息、订单数据等,确保数据的真实性和有效性。例如,商品数据应涵盖不同类别、价格区间的商品;用户信息包含各种角色和权限的用户;订单数据包含不同状态和金额的订单。
  • 预期结果:根据系统设计和业务需求,设定合理的性能指标预期值。例如,商品查询接口的平均响应时间应小于 500 毫秒,吞吐量达到每秒处理 1000 个请求以上,错误率控制在 1% 以内;用户登录接口的平均响应时间小于 300 毫秒,下单操作的成功率达到 99% 以上等。以商品查询场景为例,设置并发用户数从 100 逐步增加到 1000,每增加 100 个用户进行一轮测试,持续时间为 10 分钟,记录每轮测试的性能指标。

1.3 源码实现

在 Spring Boot 后端,以商品查询接口为例,代码示例如下:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.Product;
import com.example.demo.service.ProductService;
import java.util.List;

@RestController
public class ProductController {
    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/products")
    public List<Product> getProducts(@RequestParam(required = false) String category,
                                     @RequestParam(defaultValue = "0") int page,
                                     @RequestParam(defaultValue = "10") int size) {
        QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
        if (category != null) {
            queryWrapper.eq("category", category);
        }
        queryWrapper.last("LIMIT " + page * size + ", " + size);
        return productService.list(queryWrapper);
    }
}

在 Element Plus 前端,使用 axios 发送请求,代码示例如下:

<template>
  <div>
    <el-button @click="fetchProducts">查询商品</el-button>
    <el-table :data="products">
      <el-table-column prop="id" label="商品ID"></el-table-column>
      <el-table-column prop="name" label="商品名称"></el-table-column>
      <el-table-column prop="price" label="商品价格"></el-table-column>
    </el-table>
  </div>
</template>

<script setup>
import axios from 'axios';
import { ref } from 'vue';

const products = ref([]);

const fetchProducts = async () => {
  try {
    const response = await axios.get('/products', {
      params: {
        category: 'electronics',
        page: 0,
        size: 10
      }
    });
    products.value = response.data;
  } catch (error) {
    console.error('查询商品失败:', error);
  }
};
</script>

在 uniapp 前端,使用 uni.request 发送请求,代码示例如下:

<template>
  <view>
    <button @click="fetchProducts">查询商品</button>
    <view v-for="product in products" :key="product.id">
      <text>{{ product.name }} - {{ product.price }}</text>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      products: []
    };
  },
  methods: {
    async fetchProducts() {
      try {
        const response = await uni.request({
          url: '/products',
          method: 'GET',
          data: {
            category: 'electronics',
            page: 0,
            size: 10
          }
        });
        this.products = response.data;
      } catch (error) {
        console.error('查询商品失败:', error);
      }
    }
  }
};
</script>

二、执行压力测试与性能指标收集

2.1 模拟高并发场景

在 JMeter 中,通过配置线程组来模拟高并发场景。线程组是 JMeter 中定义虚拟用户的核心组件,通过设置线程组的相关参数,可以精确控制并发用户数、用户加载方式以及请求的循环次数等。

打开 JMeter,在测试计划中添加一个线程组。在设置线程组参数时,“线程数” 用于设定并发用户的数量,比如设置为 200,表示模拟 200 个用户同时访问系统;“Ramp-Up Period (in seconds)” 表示在指定的时间内逐步启动所有线程,若设置为 10 秒,JMeter 会在 10 秒内均匀地启动这 200 个线程,这样可以避免瞬间对服务器产生过大的压力;“循环次数” 决定每个线程发送请求的重复次数,若设置为 5,每个线程会对目标接口发送 5 次请求 ,总请求数则为线程数乘以循环次数,即 200×5 = 1000 次。此外,若勾选 “永远”,线程会一直循环发送请求,直到手动停止测试。

同时,我们还可以通过调度器来进一步控制测试的执行时间和启动延迟。“持续时间(秒)” 设定整个测试场景的运行时长,比如设置为 60 秒,测试将在启动后持续运行 60 秒;“启动延迟(秒)” 则指定从点击开始测试到真正启动线程之间的等待时间,例如设置为 5 秒,点击开始后,JMeter 会等待 5 秒再启动线程组中的线程。通过这些参数的合理配置,我们可以模拟出各种真实的高并发场景,如瞬间高并发、持续稳定并发等情况,从而全面测试商城系统在不同负载下的性能表现。

2.2 收集系统性能指标

在商城系统压力测试过程中,需要重点收集响应时间、吞吐量、错误率等关键性能指标。响应时间直接影响用户体验,指从客户端发送请求到接收到服务器响应所耗费的时间,一般包括网络传输时间、服务器处理时间等。在 JMeter 中,平均响应时间(Average)是所有请求响应时间的平均值,能反映系统在整体负载下的响应速度;中位数(Median)表示 50% 的请求响应时间小于该值,可用于衡量响应时间的集中趋势;90% Line 表示 90% 的请求响应时间小于该值,常用于评估系统在高负载下大部分用户的响应体验。

吞吐量体现了系统的处理能力,即单位时间内系统处理的请求数量,通常以 TPS(Transactions Per Second,每秒事务数)或 RPS(Requests Per Second,每秒请求数)为单位。较高的吞吐量意味着系统能够处理更多的并发请求,性能表现更优。错误率是指测试过程中出现错误的请求数量占总请求数量的百分比,错误可能包括网络超时、服务器内部错误、业务逻辑错误等。错误率过高表明系统在当前负载下存在稳定性问题,需要深入排查和优化。

在 JMeter 中,通过添加 “聚合报告” 监听器来收集这些性能指标。聚合报告以表格形式展示每个请求的各项性能数据,包括 Label(请求名称,对应 JMeter 中 HTTP Request 等元件的 Name 属性)、Samples(请求样本数,即总共发出的请求数量)、Average(平均响应时间)、Median(中位数响应时间)、90% Line(90% 百分位响应时间)、Min(最小响应时间)、Max(最大响应时间)、Error%(错误率)、Throughput(吞吐量)以及接收和发送的字节数(KB/Sec)等。通过分析这些指标数据,我们可以直观地了解系统在高并发场景下的性能状况,定位性能瓶颈所在。

2.3 源码实现

在 Spring Boot 后端,为了更好地处理高并发请求并记录性能指标,可以借助 Spring AOP(面向切面编程)和一些日志框架来实现。以商品查询接口为例,通过 AOP 可以在方法执行前后记录时间戳,从而计算出方法的执行时间,即响应时间。同时,可以使用计数器来统计请求次数,进而计算吞吐量。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class PerformanceAspect {
    private static final Logger logger = LoggerFactory.getLogger(PerformanceAspect.class);
    private static final ThreadLocal<Long> startTime = new ThreadLocal<>();
    private static long requestCount = 0;

    @Around("execution(* com.example.demo.controller.ProductController.getProducts(..))")
    public Object measurePerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        startTime.set(System.currentTimeMillis());
        try {
            return joinPoint.proceed();
        } finally {
            long endTime = System.currentTimeMillis();
            long executionTime = endTime - startTime.get();
            requestCount++;
            double throughput = requestCount * 1000.0 / executionTime;
            logger.info("商品查询接口响应时间: {} ms, 吞吐量: {} requests/second", executionTime, throughput);
            startTime.remove();
        }
    }
}

在前端,无论是 Element Plus 还是 uniapp,都可以通过封装请求函数来模拟高并发请求。以 Element Plus 为例,利用 axios 库结合 Promise.all 方法,可并发发送多个请求。

<template>
  <div>
    <el-button @click="sendConcurrentRequests">发送并发请求</el-button>
  </div>
</template>

<script setup>
import axios from 'axios';
import { ref } from 'vue';

const sendConcurrentRequests = async () => {
  const requestCount = 10;
  const requests = Array.from({ length: requestCount }, () =>
    axios.get('/products', {
      params: {
        category: 'electronics',
        page: 0,
        size: 10
      }
    })
  );
  try {
    const responses = await Promise.all(requests);
    console.log('并发请求成功:', responses);
  } catch (error) {
    console.error('并发请求失败:', error);
  }
};
</script>

在 uniapp 中,使用 uni.request 结合 Promise.all 也能实现类似的功能:

<template>
  <view>
    <button @click="sendConcurrentRequests">发送并发请求</button>
  </view>
</template>

<script>
export default {
  methods: {
    async sendConcurrentRequests() {
      const requestCount = 10;
      const requests = Array.from({ length: requestCount }, () =>
        uni.request({
          url: '/products',
          method: 'GET',
          data: {
            category: 'electronics',
            page: 0,
            size: 10
          }
        })
      );
      try {
        const responses = await Promise.all(requests.map(req => new Promise((resolve, reject) => {
          req.then(res => resolve(res)).catch(err => reject(err));
        })));
        console.log('并发请求成功:', responses);
      } catch (error) {
        console.error('并发请求失败:', error);
      }
    }
  }
};
</script>

通过上述代码,在前端可以方便地模拟高并发请求,而后端则能有效地记录和统计相关性能指标,为后续的性能分析和优化提供数据支持。

三、搭建性能监控系统

3.1 Prometheus + Grafana 介绍

Prometheus 是一款开源的系统监控和警报工具,其核心在于通过 HTTP 协议周期性地抓取被监控组件的状态数据,即采用 Pull(拉取)模式从 Exporter 获取监控指标 。这些指标以时间序列的形式存储,每个时间序列都由一个唯一的标识符(包含指标名称和一组标签)和一系列的时间戳及对应的值组成,从而构建起多维度的数据模型。Prometheus 提供了强大的 PromQL 查询语言,能够对这些时间序列数据进行灵活的查询、聚合和分析,例如计算一段时间内的平均值、最大值、最小值,或者进行比率计算等,为性能分析提供了有力支持。同时,Prometheus 还具备联邦集群能力,可从其他 Prometheus Server 实例中获取数据,实现分布式监控。

Grafana 则是一款采用 Go 语言编写的开源数据可视化和监控分析平台,主要用于大规模指标数据的可视化展现。它支持从多种数据源(如 Prometheus、InfluxDB、Elasticsearch 等)获取数据,并提供了丰富多样的可视化图表类型,包括线图、柱状图、饼图、表格、地图等。用户可以根据实际需求自由组合和定制这些图表,创建出直观、美观且富有洞察力的仪表盘,将复杂的监控数据以清晰易懂的方式呈现出来,方便运维人员和开发人员实时了解系统的运行状态,及时发现潜在问题。此外,Grafana 还具备灵活的告警功能,可根据用户设置的阈值和规则自动发送通知和警报,确保在系统出现异常时能够及时响应和处理。

将 Prometheus 与 Grafana 结合使用,Prometheus 负责数据的采集、存储和查询,Grafana 专注于数据的可视化展示和告警,两者优势互补,能够为商城系统搭建一套完整、高效的性能监控解决方案,帮助我们全面掌握系统性能状况,保障系统的稳定运行。

3.2 搭建过程

  1. 安装 Prometheus:从 Prometheus 官方网站(https://prometheus.io/download/ )下载适合系统的安装包,例如在 Linux 系统中下载prometheus-*.linux-amd64.tar.gz压缩包。解压安装包到指定目录,如/usr/local/prometheus。修改配置文件prometheus.yml,配置监控任务,例如添加对商城服务的监控任务,指定监控目标的地址和端口。启动 Prometheus,在命令行中进入 Prometheus 安装目录,执行nohup ./prometheus --config.file=prometheus.yml &命令,使其在后台运行。此时,Prometheus 会按照配置文件中的设置,定期从指定的监控目标拉取指标数据,并存储在本地的时间序列数据库中。
  2. 安装 Grafana:在 Linux 系统中,可以通过 yum 或 apt 等包管理器进行安装。例如,使用 yum 安装时,先添加 Grafana 的官方 yum 源,编辑/etc/yum.repos.d/grafana.repo文件,添加如下内容:
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt

然后执行yum install grafana -y命令进行安装。安装完成后,启动 Grafana 服务,执行systemctl start grafana-server命令,并设置开机自启systemctl enable grafana-server。通过浏览器访问http://localhost:3000(默认端口为 3000),使用默认用户名admin和密码admin登录 Grafana。登录后,系统会提示修改初始密码,设置新密码后即可进入 Grafana 主界面。

  1. Spring Boot 集成 Micrometer 暴露指标端点:在 Spring Boot 项目的pom.xml文件中添加 Micrometer 和 Prometheus 的依赖:
<dependencies>
    <!-- Micrometer Prometheus 依赖 -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
    </dependency>
    <!-- Spring Boot Actuator 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

在application.yml配置文件中进行相关配置,开启指标端点的暴露:

management:
  endpoints:
    web:
      exposure:
        include: "*"
  metrics:
    export:
      prometheus:
        enabled: true
  endpoint:
    prometheus:
      enabled: true

这样配置后,Spring Boot 应用会自动集成 Micrometer,并通过/actuator/prometheus端点暴露 Prometheus 格式的指标数据,供 Prometheus 抓取。

3.3 关联监控指标端点

  1. 修改 Prometheus 配置文件:在 Prometheus 的prometheus.yml配置文件中,添加商城服务的监控任务。假设商城服务运行在localhost:8080,添加如下配置:
scrape_configs:
  - job_name:'mall_service'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']

修改完成后,保存配置文件并重启 Prometheus 服务,使其加载新的配置。Prometheus 会按照配置,定期从localhost:8080/actuator/prometheus端点拉取商城服务的指标数据。

  1. 在 Grafana 中添加 Prometheus 数据源:登录 Grafana,点击左侧菜单栏中的齿轮图标(Configuration),选择 “Data Sources”。在数据源页面,点击 “Add data source” 按钮,选择 “Prometheus”。在配置页面中,填写 Prometheus 的访问地址,例如http://localhost:9090(根据实际情况填写),其他选项保持默认,点击 “Save & test” 按钮。如果配置正确,会显示 “Data source is working” 提示,表示 Grafana 已成功连接到 Prometheus 数据源。
  2. 导入模板展示指标:Grafana 提供了丰富的仪表盘模板,可以在 Grafana 官方网站(https://grafana.com/grafana/dashboards )上搜索并下载适合商城监控的模板。下载模板后,在 Grafana 主界面点击 “+” 号,选择 “Import”,上传下载的模板文件,或者直接输入模板 ID 进行导入。导入时,选择之前添加的 Prometheus 数据源,点击 “Import” 按钮,即可在 Grafana 中展示商城服务的各项监控指标,如响应时间、吞吐量、错误率等,以直观的图表形式呈现系统性能状态。

3.4 源码实现

  1. Spring Boot 配置文件:在application.yml文件中,除了上述开启指标端点暴露的配置外,还可以进行一些自定义配置,例如添加自定义标签:
management:
  endpoints:
    web:
      exposure:
        include: "*"
  metrics:
    export:
      prometheus:
        enabled: true
        tags:
          application: mall - service
  endpoint:
    prometheus:
      enabled: true
  1. 相关依赖:在pom.xml文件中,确保依赖的版本正确且完整,如下所示:
<dependencies>
    <!-- Micrometer Prometheus 依赖 -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-registry-prometheus</artifactId>
        <version>1.10.6</version>
    </dependency>
    <!-- Spring Boot Actuator 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <version>2.7.8</version>
    </dependency>
</dependencies>
  1. 自定义指标:在 Spring Boot 应用中,可以使用 Micrometer 提供的注解来创建自定义指标。例如,在一个服务类中添加一个计数器,统计某个业务方法的调用次数:
import io.micrometer.core.annotation.Counted;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
    @Counted(value = "order_service_invocation_count", description = "Number of times the order service method is invoked")
    public void processOrder() {
        // 业务逻辑
    }
}

通过上述配置和代码实现,商城系统的性能监控体系得以搭建完成,Prometheus 能够准确地采集系统指标数据,Grafana 则将这些数据以直观的可视化方式展示出来,为系统的性能优化和问题排查提供有力支持。

四、总结与展望

压力测试与性能监控在商城系统的全生命周期中占据着无可替代的关键地位。通过压力测试,我们能够精准地评估商城系统在高并发场景下的性能表现,提前洞察系统可能存在的性能瓶颈,为系统优化提供有力的数据支撑,从而确保系统在面对实际业务高峰时,能够稳定、高效地运行,避免因性能问题导致的用户流失和业务损失。性能监控则像是商城系统的 “实时健康监测仪”,借助 Prometheus 和 Grafana 等工具,我们能够对系统的各项性能指标进行实时、全面的监控,及时发现系统运行过程中的异常情况,做到早发现、早处理,保障系统的稳定运行。

展望未来,随着商城业务的不断拓展和用户量的持续增长,我们仍需在多个方面持续发力,进一步优化系统性能。在架构优化层面,可探索微服务架构的深度应用,将商城系统拆分为多个独立的服务模块,实现服务的独立部署、扩展和升级,提高系统的灵活性和可维护性;同时,引入分布式缓存和消息队列技术,降低数据库的访问压力,提升系统的响应速度和吞吐量。在技术应用方面,人工智能和机器学习技术的发展为性能优化开辟了新的道路,例如利用机器学习算法对历史性能数据进行分析,预测系统性能趋势,提前进行性能优化;在智能运维领域,借助人工智能实现故障的自动诊断和修复,提高运维效率。此外,随着 5G 技术的普及和物联网设备的广泛应用,商城系统将面临更多的接入设备和更高的并发请求,如何应对这些新的挑战,实现系统的无缝扩展和性能的持续提升,将是未来研究和探索的重要方向。我们相信,通过不断地优化和创新,商城系统将能够为用户提供更加优质、稳定的服务,在激烈的市场竞争中脱颖而出。


http://www.kler.cn/a/584330.html

相关文章:

  • 25年的短剧风口:广告看短剧app开发建设运营及动漫短剧执照 Ai短剧及deepseek和manus等模型Ai接口集成
  • 专题地图的立体表达-基于QGIS和PPT的“千层饼”视图制作实践
  • HTML 样式之 CSS 全面解析
  • CUDA编程之OpenCV与CUDA结合使用
  • Android Retrofit 框架日志与错误处理模块深度剖析(七)
  • Spring Boot基础使用详解
  • 第十七:go 反射
  • docker安装的es报错了?failed to obtain node locks怎么破~
  • linux - ubuntu 使用时一些小问题整理 --- 持续更新
  • 级联树SELECTTREE格式调整
  • AI智能代码疫苗技术,赋能数字化应用内生安全自免疫
  • 通义万相 2.1 × 蓝耘智算:AIGC 界的「黄金搭档」如何重塑创作未来?
  • 解析富集分析中的过表达分析(ORA):原理、应用与优化
  • Axure PR 9 中继器 05 快捷查询
  • 从3b1b到课堂:教育3D化的理想与现实鸿沟
  • 深度学习 bert与Transformer的区别联系
  • 接入手机后,DeepSeek难“转正”
  • Pytorch中矩阵乘法使用及案例
  • Manus(一种AI代理或自动化工具)与DeepSeek(一种强大的语言模型或AI能力)结合使用任务自动化和智能决策
  • 视频理解之Actionclip(论文宏观解读)