本文目录导读:

下面是一个完整的Java全链路压测案例,包含架构设计、压测工具选择、代码实现和最佳实践。
案例背景
假设我们要对一个电商系统的下单流程进行全链路压测,链路包含:
用户请求 → Nginx → Spring Cloud Gateway → 用户服务 → 订单服务 → 库存服务 → 支付服务
压测架构设计
整体架构
压测架构: 压测工具: [Apache JMeter/Gatling/自研压测平台] 压测入口: Nginx集群(负载均衡) 链路组件: [Gateway, 用户服务, 订单服务, 库存服务, 支付服务] 数据支撑: [MySQL, Redis, MQ, 分布式缓存] 监控系统: [Prometheus + Grafana + 日志中心]
核心配置示例
# application.yml 压测配置
spring:
profiles: stress-test
server:
tomcat:
max-threads: 200
min-spare-threads: 50
accept-count: 100
connection-timeout: 3000
stress:
enabled: true
mode: full-link
# JMeter压测配置
Thread Group:
Number of Threads: 500
Ramp-Up Period: 60
Loop Count: 100
HTTP Request:
Protocol: http
Server: 10.0.0.100
Port: 8080
Method: POST
Path: /api/order/create
核心代码实现
压测链路服务改造
// 用户服务 - 预留压测专用接口
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/login")
public Result<UserInfo> login(@RequestBody LoginRequest request) {
// 正常业务逻辑
return userService.login(request);
}
@PostMapping("/login/test")
@StressTest (不落库,只做内存操作)
public Result<UserInfo> loginTest(@RequestBody LoginRequest request) {
// 压测专用,不操作数据库,只返回模拟数据
return Result.success(mockUserInfo(request.getUsername()));
}
}
// 订单服务 - 异步链路支持
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
@Override
@Transactional(rollbackFor = Exception.class)
public OrderResult createOrder(OrderRequest request) {
// 判断是否为压测请求
if (StressTestContext.isStressTest()) {
return createMockOrder(request);
}
try {
// 1. 创建订单
Order order = buildOrder(request);
orderMapper.insert(order);
// 2. 扣减库存
inventoryService.deductStock(order);
// 3. 调用支付
paymentService.pay(order);
return OrderResult.success(order);
} catch (Exception e) {
log.error("创建订单失败", e);
return OrderResult.fail(e.getMessage());
}
}
// 压测专用:不落库,走内存队列
private OrderResult createMockOrder(OrderRequest request) {
Order order = buildOrder(request);
order.setOrderNo("MOCK-" + System.currentTimeMillis());
// 放内存队列,不落库
mockOrderQueue.offer(order);
return OrderResult.success(order);
}
}
// 库存服务 - 缓存优先设计
@Service
@Slf4j
public class InventoryServiceImpl implements InventoryService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private InventoryMapper inventoryMapper;
@Override
public Boolean deductStock(Order order) {
// 压测请求直接返回成功
if (StressTestContext.isStressTest()) {
return true;
}
// 先查Redis
String key = "stock:" + order.getProductId();
Long stock = redisTemplate.opsForValue().decrement(key);
if (stock < 0) {
// 库存不足,回滚
redisTemplate.opsForValue().increment(key);
throw new BusinessException("库存不足");
}
// 异步同步到数据库
asyncSyncStock(order.getProductId(), stock);
return true;
}
}
// 压测上下文工具类
@Component
public class StressTestContext {
private static final ThreadLocal<Boolean> STRESS_TEST_FLAG = new ThreadLocal<>();
private static final Queue<Order> MOCK_ORDER_QUEUE = new ConcurrentLinkedQueue<>();
private static volatile boolean isStressTestMode = false;
public static void setStressTest(boolean isStressTest) {
STRESS_TEST_FLAG.set(isStressTest);
}
public static boolean isStressTest() {
return Boolean.TRUE.equals(STRESS_TEST_FLAG.get()) || isStressTestMode;
}
public static void setStressTestMode(boolean mode) {
isStressTestMode = mode;
}
public static void clear() {
STRESS_TEST_FLAG.remove();
}
}
// 过滤器 - 识别压测请求
@Component
public class StressTestFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String stressTestFlag = httpRequest.getHeader("X-Stress-Test");
if ("true".equals(stressTestFlag)) {
StressTestContext.setStressTest(true);
// 添加压测标记到MDC,便于日志追踪
MDC.put("stressTest", "true");
}
try {
chain.doFilter(request, response);
} finally {
StressTestContext.clear();
MDC.clear();
}
}
}
JMeter压测脚本配置
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.0" properties="5.0">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="电商系统全链路压测">
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="SERVER" elementType="Argument">
<stringProp name="Argument.name">SERVER</stringProp>
<stringProp name="Argument.value">10.0.0.100</stringProp>
</elementProp>
<elementProp name="PORT" elementType="Argument">
<stringProp name="Argument.name">PORT</stringProp>
<stringProp name="Argument.value">8080</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<hashTree>
<!-- 线程组配置 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="全链路压力测试">
<stringProp name="ThreadGroup.num_threads">500</stringProp>
<stringProp name="ThreadGroup.ramp_time">60</stringProp>
<stringProp name="ThreadGroup.duration">300</stringProp>
<boolProp name="ThreadGroup.scheduler">true</boolProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController">
<stringProp name="LoopController.loops">-1</stringProp>
</elementProp>
<hashTree>
<!-- 登录请求 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="用户登录">
<stringProp name="HTTPSampler.domain">${SERVER}</stringProp>
<stringProp name="HTTPSampler.port">${PORT}</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<stringProp name="HTTPSampler.path">/api/user/login</stringProp>
<stringProp name="HTTPSampler.connect_timeout">5000</stringProp>
<stringProp name="HTTPSampler.response_timeout">10000</stringProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="request" elementType="HTTPArgument">
<stringProp name="Argument.name">request</stringProp>
<stringProp name="Argument.value">{"username":"testUser${__Random(1,1000)}","password":"123456"}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<!-- 创建订单请求 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="创建订单">
<stringProp name="HTTPSampler.domain">${SERVER}</stringProp>
<stringProp name="HTTPSampler.port">${PORT}</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
<stringProp name="HTTPSampler.path">/api/order/create</stringProp>
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="token" elementType="HTTPArgument">
<stringProp name="Argument.name">token</stringProp>
<stringProp name="Argument.value">${login_token}</stringProp>
</elementProp>
<elementProp name="request" elementType="HTTPArgument">
<stringProp name="Argument.name">request</stringProp>
<stringProp name="Argument.value">{"productId":1001,"quantity":1,"userId":"testUser"}</stringProp>
</elementProp>
</collectionProp>
</elementProp>
</HTTPSamplerProxy>
<!-- 进行链路检查 -->
<ResponseAssertion guiclass="ResponseAssertionGui" testclass="ResponseAssertion" testname="响应断言">
<collectionProp name="Asserion.test_strings">
<stringProp name="49586">success</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_message</stringProp>
</ResponseAssertion>
</hashTree>
</ThreadGroup>
</hashTree>
</TestPlan>
</hashTree>
</jmeterTestPlan>
监控与性能分析
// 性能指标收集器
@Aspect
@Component
public class PerformanceMonitor {
private static final MeterRegistry meterRegistry = new SimpleMeterRegistry();
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
@Around("serviceLayer()")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
Timer.Sample sample = Timer.start(meterRegistry);
String methodName = joinPoint.getSignature().getName();
try {
Object result = joinPoint.proceed();
// 记录成功率
meterRegistry.counter("method_success_count", "method", methodName).increment();
return result;
} catch (Exception e) {
// 记录失败
meterRegistry.counter("method_failure_count", "method", methodName, "error", e.getMessage()).increment();
throw e;
} finally {
sample.stop(Timer.builder("method_execution_time")
.tag("method", methodName)
.register(meterRegistry));
}
}
}
压测数据准备
-- 创建压测用户表
CREATE TABLE stress_test_user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
password VARCHAR(50),
is_stress BOOLEAN DEFAULT TRUE,
created_time TIMESTAMP
);
-- 创建压测商品表
CREATE TABLE stress_test_product (
id BIGINT PRIMARY KEY,
product_name VARCHAR(100),
price DECIMAL(10,2),
stock INT,
is_stress BOOLEAN DEFAULT TRUE
);
-- 初始化数据脚本
DELIMITER $$
CREATE PROCEDURE init_stress_data()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i <= 10000 DO
INSERT INTO stress_test_user (username, password, is_stress)
VALUES (CONCAT('stress_', i), MD5('123456'), TRUE);
SET i = i + 1;
END WHILE;
END$$
DELIMITER ;
CALL init_stress_data();
压测执行步骤
环境准备
# 启动压测环境 docker-compose -f stress-test-environment.yml up -d # 初始化数据 mysql -h localhost -u root -p < init_data.sql # 启动服务(去掉本地依赖) nohup java -jar user-service.jar --spring.profiles.active=stress & nohup java -jar order-service.jar --spring.profiles.active=stress &
执行压测
# 使用JMeter命令执行
jmeter -n -t full-link-stress-test.jmx -l results.jtl -j stress-log.log -e -o report
# 使用Gatling执行
gatling.sh -s fullLink.StressTestSimulation
# 或使用自研压测平台
curl -X POST http://stress-platform:8080/api/stress/start \
-H "Content-Type: application/json" \
-d '{"scenarioId": 1, "concurrency": 500, "duration": 300}'
监控指标采集
// 压测监控数据
public class StressMetrics {
// 吞吐量
private double requestsPerSecond;
// 平均响应时间
private double averageResponseTime;
// P99响应时间
private double p99ResponseTime;
// 错误率
private double errorRate;
// CPU使用率
private double cpuUsage;
// 内存使用率
private double memoryUsage;
// 线程池状态
private int activeThreads;
private int queueSize;
}
最佳实践
压测隔离策略
隔离策略: 数据库隔离: 使用独立压测数据库或压测专用表 缓存隔离: 使用独立Redis实例 MQ隔离: 使用独立Topic 流量控制: 在网关层识别压测流量
常见问题处理
@Component
public class StressTestConfig {
// 动态调整连接池
@EventListener
public void handleStressStart(StressStartEvent event) {
// 调整线程池
threadPoolConfig.setCorePoolSize(event.getConcurrency());
threadPoolConfig.setMaxPoolSize(event.getConcurrency() * 2);
// 调整数据库连接池
hikariConfig.setMaximumPoolSize(event.getConcurrency());
// 调整MQ消费者并发数
rocketMQConsumer.setConsumeThreadNumber(event.getConcurrency());
}
// 压测结束恢复配置
@EventListener
public void handleStressEnd(StressStopEvent event) {
threadPoolConfig.restore();
hikariConfig.restore();
rocketMQConsumer.restore();
}
}
压测报告模板
# 压测报告 - 电商系统全链路压力测试 - 测试日期: 2024-01-15 - 测试环境: 生产环境3节点集群 - 压测工具: Apache JMeter 5.5 ## 测试结果 ### 总体指标 | 指标 | 结果 | |------|------| | 并发用户数 | 500 | | 最大TPS | 980.5 | | 平均响应时间 | 850ms | | P95响应时间 | 1.2s | | P99响应时间 | 2.1s | | 错误率 | 1.2% | ### 系统资源 | 服务 | CPU使用率 | 内存使用率 | 磁盘I/O | |------|-----------|------------|---------| | Gateway | 65% | 70% | 45% | | 用户服务 | 45% | 55% | 30% | | 订单服务 | 78% | 82% | 65% | | 库存服务 | 52% | 60% | 40% | ### 性能瓶颈分析 1. 订单服务MySQL连接池达到上限 2. 库存服务Redis读写偏高 3. Gateway线程数不足 ### 优化建议 1. 增加数据库连接池到200 2. Redis主从改为集群架构 3. Gateway增加线程池和灰度控制
完整压测代码仓库示例
project/
├── pom.xml
├── src/
│ └── main/
│ ├── java/
│ │ └── com/example/
│ │ ├── controller/
│ │ ├── service/
│ │ ├── config/
│ │ ├── filter/
│ │ └── monitor/
│ └── resources/
│ ├── application.yml
│ └── stress-test.jmx
├── stress-environment/
│ └── docker-compose.yml
└── scripts/
├── build.sh
├── deploy.sh
└── run-stress-test.sh
这个案例涵盖了Java全链路压测的完整流程,包括架构设计、代码实现、压测执行和监控分析,根据实际业务需求,可以调整具体的技术栈和配置。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播