性能测试:JMeter/Gatling/K6
性能测试:JMeter/Gatling/K6
JMeter性能测试
JMeter是Apache开源的性能测试工具,支持多种协议和丰富的测试场景。
// JMeter测试计划配置
@Component
public class JMeterTestPlan {
public TestPlan createAPITestPlan(String baseUrl) {
TestPlan testPlan = new TestPlan("API性能测试");
// 线程组
ThreadGroup threadGroup = new ThreadGroup("API请求线程");
threadGroup.setNumThreads(100);
threadGroup.setRampUp(60);
threadGroup.setDuration(600);
threadGroup.setScheduler(true);
// HTTP请求
HTTPSampler sampler = new HTTPSampler();
sampler.setUrl(baseUrl + "/api/data");
sampler.setMethod("GET");
sampler.setConnectTimeout(5000);
sampler.setResponseTimeout(30000);
// 请求头管理器
HeaderManager headerManager = new HeaderManager();
headerManager.add(new HTTPSampler.Header("Content-Type", "application/json"));
headerManager.add(new HTTPSampler.Header("Authorization", "Bearer ${token}"));
// 断言
ResponseAssertion assertion = new ResponseAssertion();
assertion.setTestField("response_code");
assertion.setPattern("200");
// 监听器
SummaryReport report = new SummaryReport();
AggregateReport aggregateReport = new AggregateReport();
ViewResultsFullVisualizer resultsVisualizer = new ViewResultsFullVisualizer();
testPlan.add(threadGroup);
threadGroup.add(headerManager);
threadGroup.add(sampler);
sampler.add(assertion);
threadGroup.add(report);
threadGroup.add(aggregateReport);
threadGroup.add(resultsVisualizer);
return testPlan;
}
}
// JMeter脚本生成
@Component
public class JMeterScriptGenerator {
public String generateScript(TestConfig config) {
StringBuilder script = new StringBuilder();
script.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
script.append("<jmeterTestPlan version=\"1.2\">\n");
script.append(" <hashTree>\n");
script.append(" <TestPlan guiclass=\"TestPlanGui\" ");
script.append("testclass=\"TestPlan\" testname=\"Performance Test\">\n");
// 线程组
script.append(" <elementProp name=\"ThreadGroup.main\" ");
script.append("elementType=\"ThreadGroup\" ");
script.append("guiclass=\"ThreadGroupGui\" ");
script.append("testclass=\"ThreadGroup\" ");
script.append("testname=\"Thread Group\">\n");
script.append(" <stringProp name=\"ThreadGroup.num_threads\">");
script.append(config.getThreadCount()).append("</stringProp>\n");
script.append(" <stringProp name=\"ThreadGroup.ramp_time\">");
script.append(config.getRampUpTime()).append("</stringProp>\n");
script.append(" </elementProp>\n");
script.append(" </TestPlan>\n");
script.append(" </hashTree>\n");
script.append("</jmeterTestPlan>\n");
return script.toString();
}
}
Gatling性能测试
Gatling是基于Scala的高性能测试工具,以代码即测试的理念著称。
// Gatling测试脚本
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class ApiSimulation extends Simulation {
val httpProtocol = http
.baseUrl("http://localhost:8080")
.acceptHeader("application/json")
.contentTypeHeader("application/json")
val scn = scenario("API Test")
.exec(http("Get Data")
.get("/api/data")
.check(status.is(200))
.check(jsonPath("$.result").exists))
.pause(1)
.exec(http("Create Data")
.post("/api/data")
.body(StringBody("""{"key": "value"}"""))
.check(status.is(201))
.check(jsonPath("$.id").saveAs("dataId")))
.pause(1)
.exec(http("Get Created Data")
.get("/api/data/${dataId}")
.check(status.is(200)))
setUp(
scn.inject(
rampUsers(100).during(60.seconds),
constantUsersPerSec(10).during(5.minutes)
)
).protocols(httpProtocol)
}
// Gatling高级配置
class AdvancedSimulation extends Simulation {
// 自定义 feeder
val userFeeder = Iterator.continually {
Map(
"userId" -> java.util.UUID.randomUUID().toString,
"timestamp" -> System.currentTimeMillis()
)
}
// 自定义检查
def customCheck(response: io.gatling.http.response.Response): Boolean = {
response.body.string.exists(_.contains("success"))
}
val scn = scenario("Advanced Test")
.feed(userFeeder)
.exec(http("Request")
.get("/api/users/${userId}")
.check(customCheck _))
.doIf("#{statusCode == 200}") {
exec(http("Success")
.get("/api/success"))
}
setUp(
scn.inject(
nothingFor(5.seconds),
atOnceUsers(10),
rampUsers(100).during(10.seconds),
constantUsersPerSec(20).during(1.minute),
rampUsersPerSec(10).to(50).during(2.minutes)
)
).protocols(httpProtocol)
.assertions(
global.responseTime.max.lt(1000),
global.successfulRequests.percent.gt(95.0)
)
}
K6性能测试
K6是基于Go和JavaScript的现代性能测试工具,专注于开发者体验。
// K6测试脚本
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';
// 自定义指标
const errorRate = new Rate('errors');
const duration = new Trend('duration');
export const options = {
stages: [
{ duration: '30s', target: 20 }, // 30秒内增加到20用户
{ duration: '1m', target: 20 }, // 保持20用户1分钟
{ duration: '30s', target: 50 }, // 30秒内增加到50用户
{ duration: '1m', target: 50 }, // 保持50用户1分钟
{ duration: '30s', target: 0 }, // 30秒内减少到0用户
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95%的请求响应时间小于500ms
http_req_failed: ['rate<0.1'], // 错误率小于10%
errors: ['rate<0.1'],
},
};
export default function () {
const response = http.get('http://localhost:8080/api/data');
check(response, {
'status is 200': (r) => r.status === 200,
'response time < 500ms': (r) => r.timings.duration < 500,
'response has data': (r) => r.json().data !== null,
});
errorRate.add(response.status !== 200);
duration.add(response.timings.duration);
sleep(1);
}
// 高级配置
export const options = {
scenarios: {
// 场景1:基准测试
baseline: {
executor: 'constant-vus',
vus: 10,
duration: '2m',
exec: 'baselineTest',
},
// 场景2:负载测试
load: {
executor: 'ramping-vus',
startVUs: 0,
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 100 },
{ duration: '2m', target: 0 },
],
exec: 'loadTest',
},
// 场景3:压力测试
stress: {
executor: 'ramping-arrival-rate',
startRate: 100,
timeUnit: '1s',
preAllocatedVUs: 100,
stages: [
{ duration: '2m', target: 100 },
{ duration: '5m', target: 500 },
{ duration: '2m', target: 100 },
],
exec: 'stressTest',
},
},
};
测试工具对比
# 性能测试工具对比
testing_tools:
jmeter:
name: "JMeter"
language: "Java"
protocol_support:
- HTTP/HTTPS
- FTP
- JDBC
- SOAP/REST
- JMS
- LDAP
pros:
- 协议支持广泛
- GUI友好
- 插件丰富
- 社区活跃
cons:
- 资源占用高
- 脚本复杂
- 分布式测试配置复杂
best_for: "企业级应用,多协议测试"
gatling:
name: "Gatling"
language: "Scala"
protocol_support:
- HTTP/HTTPS
- WebSocket
- JMS
pros:
- 高性能
- 代码即测试
- 详细的报告
- CI/CD集成好
cons:
- 学习曲线陡峭
- 协议支持有限
best_for: "Web应用,API测试"
k6:
name: "K6"
language: "JavaScript"
protocol_support:
- HTTP/HTTPS
- WebSocket
- gRPC
- MQTT
pros:
- 现代化设计
- 开发者友好
- 性能优秀
- 云原生支持
cons:
- 相对较新
- 企业级功能有限
best_for: "微服务,云原生应用"
测试报告分析
// 测试报告生成
@Component
public class TestReportGenerator {
public TestReport generateReport(List<TestResult> results) {
TestReport report = new TestReport();
// 计算关键指标
double avgResponseTime = results.stream()
.mapToLong(TestResult::getResponseTime)
.average()
.orElse(0);
double p95ResponseTime = results.stream()
.mapToLong(TestResult::getResponseTime)
.sorted()
.skip((long) (results.size() * 0.95))
.findFirst()
.orElse(0);
double p99ResponseTime = results.stream()
.mapToLong(TestResult::getResponseTime)
.sorted()
.skip((long) (results.size() * 0.99))
.findFirst()
.orElse(0);
long totalRequests = results.size();
long failedRequests = results.stream()
.filter(r -> !r.isSuccess())
.count();
double throughput = totalRequests /
(results.get(results.size() - 1).getTimestamp() -
results.get(0).getTimestamp()) * 1000;
report.setAvgResponseTime(avgResponseTime);
report.setP95ResponseTime(p95ResponseTime);
report.setP99ResponseTime(p99ResponseTime);
report.setTotalRequests(totalRequests);
report.setFailedRequests(failedRequests);
report.setSuccessRate((double) (totalRequests - failedRequests) / totalRequests * 100);
report.setThroughput(throughput);
return report;
}
// 性能瓶颈分析
public List<Bottleneck> analyzeBottlenecks(TestReport report) {
List<Bottleneck> bottlenecks = new ArrayList<>();
// 响应时间分析
if (report.getP95ResponseTime() > 1000) {
bottlenecks.add(Bottleneck.builder()
.type("响应时间")
.description("P95响应时间超过1秒")
.severity("HIGH")
.suggestion("优化慢查询,增加缓存")
.build());
}
// 错误率分析
if (report.getErrorRate() > 1) {
bottlenecks.add(Bottleneck.builder()
.type("错误率")
.description("错误率超过1%")
.severity("MEDIUM")
.suggestion("检查错误日志,修复异常")
.build());
}
// 吞吐量分析
if (report.getThroughput() < 100) {
bottlenecks.add(Bottleneck.builder()
.type("吞吐量")
.description("吞吐量低于100 TPS")
.severity("MEDIUM")
.suggestion("优化代码,增加并发处理能力")
.build());
}
return bottlenecks;
}
}
性能测试工具各有特点,JMeter适合企业级多协议测试,Gatling适合Web应用测试,K6适合现代云原生应用,选择时需根据项目需求和技术栈决定。