温馨提示×

Rust 在 Ubuntu 上如何进行性能测试

小樊
34
2025-12-26 08:30:56
栏目: 编程语言

Rust 在 Ubuntu 上的性能测试实践

一 测试类型与工具选型

  • 微基准测试:使用 Criterion.rs 对函数/算法进行统计化对比,生成图表报告,适合评估小粒度改动(如不同实现、不同参数)的性能差异。
  • HTTP 负载与压力测试:使用 wrk/wrk2(轻量、命令行、高并发)或 k6(脚本化、场景化、阈值与指标丰富),验证 API 的吞吐量、延迟与稳定性。
  • 运行时与系统层分析:使用 perfvalgrindcargo flamegraph 定位 CPU 热点、内存与调用栈瓶颈;配合 tracing 与日志增强可观测性。

二 微基准测试 Criterion.rs

  • 安装依赖(Ubuntu):
    • 安装绘图工具:sudo apt-get install gnuplot
    • 项目依赖(Cargo.toml):
      [dev-dependencies]
      criterion = { version = "0.5", features = ["html_reports"] }
      
      [[bench]]
      name = "my_benchmarks"
      harness = false
      
  • 示例基准(benches/my_benchmarks.rs):
    use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId, black_box};
    
    fn fib_rec(n: u64) -> u64 {
        match n { 0 | 1 => 1, n => fib_rec(n - 1) + fib_rec(n - 2) }
    }
    fn fib_iter(n: u64) -> u64 {
        let (mut a, mut b) = (0, 1);
        for _ in 0..n { let c = a + b; a = b; b = c; }
        b
    }
    
    fn bench_fib(c: &mut Criterion) {
        let mut g = c.benchmark_group("Fibonacci");
        for n in [10, 20, 30].iter() {
            g.bench_with_input(BenchmarkId::new("Recursive", n), n, |b, &i| {
                b.iter(|| fib_rec(black_box(i)))
            });
            g.bench_with_input(BenchmarkId::new("Iterative", n), n, |b, &i| {
                b.iter(|| fib_iter(black_box(i)))
            });
        }
        g.finish();
    }
    
    criterion_group!(benches, bench_fib);
    criterion_main!(benches);
    
  • 运行与分析:
    • 执行:cargo bench
    • 查看:控制台统计与 target/criterion/ 下的 HTML 报告(含分位数、回归检测)。

三 HTTP 负载与压力测试

  • 被测服务示例(actix-web,端口 8080):
    use actix_web::{get, App, HttpResponse, HttpServer, Responder};
    #[get("/api/hello")]
    async fn hello() -> impl Responder {
        HttpResponse::Ok().body("Hello, World!")
    }
    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
        HttpServer::new(|| App::new().service(hello))
            .bind("127.0.0.1:8080")?
            .run()
            .await
    }
    
  • 使用 wrk 进行基线压测(Ubuntu 安装:sudo apt-get install wrk):
    • 命令:wrk -t12 -c400 -d30s http://localhost:8080/api/hello
    • 常用参数:-t 线程数、-c 并发连接数、-d 持续时间
  • 使用 k6 进行场景化压测(Ubuntu 安装:sudo apt-get install k6):
    • 脚本 test.js:
      import http from 'k6/http';
      import { check, sleep } from 'k6';
      export let options = {
        stages: [
          { duration: '30s', target: 100 },
          { duration: '1m',  target: 100 },
          { duration: '30s', target: 0 },
        ],
      };
      export default function () {
        let res = http.get('http://localhost:8080/api/hello');
        check(res, { 'status is 200': r => r.status === 200 });
        sleep(1);
      }
      
    • 运行:k6 run test.js
  • 关注指标:吞吐量(Requests/sec)平均/P95/P99 延迟错误率;必要时配合 Prometheus + Grafanatracing 日志做全链路观测。

四 运行时与系统层分析

  • CPU 热点与火焰图:
    • 采样:sudo perf record -g ./target/release/your_app
    • 报告:sudo perf report
    • 火焰图:cargo install flamegraph && cargo flamegraph(生成 flamegraph.svg 直观查看热点)
  • 内存与调用分析:
    • valgrind --tool=callgrind 进行调用图与缓存命中分析
  • 资源监控:
    • top/htop、glances 观察 CPU、内存、I/O 使用
    • 作为服务运行时,使用 journalctl -u your_app 查看日志;在代码中使用 log/env_loggertracing 输出关键路径耗时。

五 实践建议与常见瓶颈

  • 构建与运行:性能测试务必使用 –release 发布构建,避免调试开销影响结果。
  • 稳定复现:在 隔离环境 执行(避免其他负载干扰),预热 后再采集数据,多次运行取稳定区间。
  • 指标口径:统一记录 吞吐量、P50/P95/P99、错误率,并在报告中标注 并发数、压测时长、实例规格
  • 常见瓶颈与对策:
    • 数据库连接池过小 导致排队(如默认仅 5 个连接),可适当增大并合理设置生命周期;
    • N+1 查询 引发大量往返,改为 JOIN 并补充索引;
    • CPU 密集型任务(如 Argon2 哈希) 在异步路径中应使用 spawn_blocking 避免阻塞运行时线程;
    • 会话/缓存读写频繁 时评估序列化与网络延迟,必要时引入本地缓存或批量写入。

0