Skip to content

Latest commit

 

History

History
949 lines (694 loc) · 23.3 KB

File metadata and controls

949 lines (694 loc) · 23.3 KB

QAExchange 性能基准测试报告

本文档提供 QAExchange 系统的完整性能基准测试数据和测试方法。


📖 目录


测试环境

硬件配置

组件 规格
CPU AMD Ryzen 9 5950X (16 核 32 线程) @ 3.4GHz
内存 64 GB DDR4 3200MHz
存储 NVMe SSD 1TB (读: 3500MB/s, 写: 3000MB/s)
网络 10 Gbps Ethernet
操作系统 Ubuntu 22.04 LTS

软件环境

组件 版本
Rust 1.91.0-nightly
编译模式 Release (--release)
优化级别 opt-level = 3
LTO Enabled (thin)
qars Latest (path = "../qars2")

测试工具

  • 吞吐量测试: Apache Bench (ab)
  • 延迟测试: 自定义 Rust benchmark (criterion)
  • 压力测试: Gatling
  • 性能分析: flamegraph, perf, valgrind
  • 网络测试: iperf3, tcpdump

核心性能指标

性能目标 vs 实际表现

指标 目标 实际 P50 实际 P99 实际 P999 状态
订单吞吐量 > 100K/s 150K/s 145K/s 140K/s ✅ 超标
撮合延迟 P99 < 100μs 45μs 85μs 120μs ✅ 达标
市场数据延迟 P99 < 10μs 3μs 8μs 12μs ✅ 达标
WAL 写入延迟 P99 < 50ms 12ms 35ms 48ms ✅ 达标
MemTable 写入 P99 < 10μs 2μs 7μs 11μs ✅ 接近
SSTable 读取 P99 < 50μs 18μs 42μs 65μs ✅ 接近
WebSocket 推送 P99 < 1ms 0.3ms 0.8ms 1.2ms ✅ 接近
并发账户 > 10,000 15,000 - - ✅ 超标
WebSocket 连接 > 10,000 12,000 - - ✅ 超标

结论: 所有核心指标均达到或超过设计目标。


交易引擎性能

1. 订单提交吞吐量

测试场景: 并发提交限价单

测试代码:

#[bench]
fn bench_order_submission(b: &mut Bencher) {
    let engine = create_test_engine();
    let order = create_test_order();

    b.iter(|| {
        engine.submit_order(order.clone())
    });
}

测试结果:

并发数 吞吐量 (orders/s) P50 延迟 P99 延迟 P999 延迟
1 165,000 6 μs 12 μs 18 μs
10 158,000 60 μs 95 μs 125 μs
100 150,000 650 μs 890 μs 1.2 ms
1,000 145,000 6.5 ms 8.9 ms 12 ms

结论: 单核吞吐量 165K/s,多核并发下仍可维持 145K/s。


2. 撮合延迟

测试场景: 两笔对手单撮合成交

测试方法:

  1. 提交 BUY 限价单
  2. 立即提交 SELL 限价单(价格相同)
  3. 测量从提交到成交回调的时间

测试代码:

#[bench]
fn bench_matching_latency(b: &mut Bencher) {
    let engine = create_test_engine();

    b.iter(|| {
        let start = Instant::now();

        // 提交买单
        engine.submit_order(buy_order.clone());

        // 提交卖单(立即成交)
        engine.submit_order(sell_order.clone());

        // 等待成交
        let trade = engine.wait_for_trade();

        start.elapsed()
    });
}

测试结果 (单核):

订单簿深度 P50 延迟 P95 延迟 P99 延迟 P999 延迟
10 档 35 μs 65 μs 82 μs 105 μs
100 档 42 μs 72 μs 88 μs 115 μs
1000 档 48 μs 78 μs 95 μs 125 μs
10000 档 55 μs 85 μs 102 μs 135 μs

延迟分布图:

延迟 (μs)  累计百分比
0-20       15%
20-40      50% (P50 = 35μs)
40-60      80%
60-80      95% (P95 = 65μs)
80-100     99% (P99 = 82μs)
100-120    99.9% (P999 = 105μs)

结论: 即使订单簿深度达到 10K 档,P99 延迟仍 < 105μs,满足高频交易要求。


3. 市场数据广播延迟

测试场景: 成交发生 → 市场数据推送到订阅者

测试方法:

  1. 订阅者订阅行情
  2. 触发成交
  3. 测量订阅者收到 Tick 数据的延迟

测试代码:

#[bench]
fn bench_market_data_broadcast(b: &mut Bencher) {
    let broadcaster = MarketDataBroadcaster::new();
    let (tx, rx) = crossbeam::channel::unbounded();
    broadcaster.subscribe(tx);

    b.iter(|| {
        let start = Instant::now();

        // 广播 Tick
        broadcaster.broadcast_tick(tick.clone());

        // 等待接收
        let received_tick = rx.recv().unwrap();

        start.elapsed()
    });
}

测试结果:

订阅者数量 P50 延迟 P95 延迟 P99 延迟 吞吐量 (msg/s)
1 1.5 μs 3.2 μs 4.8 μs 650K
10 2.8 μs 5.5 μs 7.2 μs 350K
100 3.5 μs 6.8 μs 9.5 μs 280K
1,000 4.2 μs 7.5 μs 10.2 μs 230K
10,000 5.8 μs 9.2 μs 12.5 μs 170K

结论: 使用 crossbeam::channel 实现的零拷贝广播,即使 10K 订阅者,P99 延迟仍 < 15μs。


存储系统性能

1. WAL 写入性能

测试场景: 批量写入交易记录到 WAL

测试代码:

#[bench]
fn bench_wal_write(b: &mut Bencher) {
    let wal = WALManager::new("data/wal/");
    let record = create_test_record();

    b.iter(|| {
        wal.append_record(&record)
    });
}

单条写入性能:

记录大小 P50 延迟 P95 延迟 P99 延迟 吞吐量 (records/s)
128 B 8 ms 18 ms 28 ms 125
512 B 10 ms 22 ms 35 ms 100
1 KB 12 ms 25 ms 40 ms 83
4 KB 18 ms 35 ms 48 ms 55

批量写入性能 (batch_size = 1000):

记录大小 总延迟 每条延迟 吞吐量 (records/s)
128 B 120 ms 0.12 ms 78,000
512 B 180 ms 0.18 ms 52,000
1 KB 250 ms 0.25 ms 40,000
4 KB 800 ms 0.80 ms 12,500

结论: 批量写入吞吐量提升 600x(单条 125/s → 批量 78K/s)。


2. MemTable 性能

测试场景: 写入和读取 SkipMap MemTable

写入性能:

操作 P50 延迟 P95 延迟 P99 延迟 吞吐量 (ops/s)
Insert 1.8 μs 5.2 μs 7.5 μs 550K
Update 2.1 μs 5.8 μs 8.2 μs 480K
Delete 1.5 μs 4.5 μs 6.8 μs 650K

读取性能:

MemTable 大小 P50 延迟 P95 延迟 P99 延迟 吞吐量 (ops/s)
1K entries 0.8 μs 2.2 μs 3.5 μs 1.2M
10K entries 1.2 μs 3.5 μs 5.2 μs 850K
100K entries 1.8 μs 4.8 μs 7.2 μs 550K
1M entries 2.5 μs 6.5 μs 9.8 μs 400K

Flush 性能 (64 MB MemTable):

SSTable 格式 Flush 时间 吞吐量 (MB/s)
rkyv (OLTP) 450 ms 142 MB/s
Parquet (OLAP) 820 ms 78 MB/s

结论: SkipMap 提供微秒级读写,符合 OLTP 低延迟要求。


3. SSTable 性能

OLTP SSTable (rkyv + mmap) 读取性能:

SSTable 大小 Bloom Filter P50 延迟 P95 延迟 P99 延迟
64 MB 启用 12 μs 28 μs 42 μs
64 MB 禁用 18 μs 45 μs 68 μs
256 MB 启用 15 μs 32 μs 48 μs
256 MB 禁用 22 μs 52 μs 78 μs
1 GB 启用 18 μs 38 μs 55 μs
1 GB 禁用 28 μs 65 μs 92 μs

Bloom Filter 性能提升:

  • 减少无效磁盘读取 98% (1% 假阳性率)
  • 查询延迟降低 30-40%

OLAP SSTable (Parquet) 扫描性能:

文件大小 扫描范围 延迟 吞吐量 (MB/s) 吞吐量 (rows/s)
100 MB 全表 85 ms 1,200 MB/s 15M
100 MB 50% 谓词 42 ms 2,400 MB/s 30M
500 MB 全表 420 ms 1,190 MB/s 14.8M
500 MB 10% 谓词 45 ms 11,000 MB/s 137M

列裁剪性能提升:

SELECT order_id, volume FROM trades  # 只读 2 列
vs
SELECT * FROM trades                  # 读全部 15 列

性能提升: 7.5x

4. Compaction 性能

Leveled Compaction 测试:

场景 Level 0 文件数 Level 1 文件数 Compaction 时间 写放大
小规模 4 0 1.2 s 2.0x
中规模 8 3 3.5 s 2.5x
大规模 12 8 8.2 s 3.2x

写放大计算:

写放大 = (写入磁盘总字节数) / (用户写入字节数)

例: 用户写入 100 MB → Compaction 后磁盘实际写入 250 MB
写放大 = 250 / 100 = 2.5x

读放大:

最坏情况读放大 = Level 数量
Level 0-3: 最多读取 4 个 SSTable

使用 Bloom Filter: 平均读放大 1.02x (几乎无放大)

5. 查询引擎性能 (Polars)

SQL 查询性能:

查询类型 数据量 延迟 吞吐量 (rows/s)
SELECT * LIMIT 100 1M rows 8 ms 12.5M
WHERE 过滤 (10% 选择率) 1M rows 35 ms 28.6M
WHERE 过滤 (1% 选择率) 1M rows 18 ms 55.6M
GROUP BY + SUM 1M rows 85 ms 11.8M
JOIN (1:N) 100K x 1M 420 ms 238K
ORDER BY + LIMIT 1000 1M rows 92 ms 10.9M

时间序列查询 (30 天数据):

时间粒度 原始数据量 聚合后数据量 延迟
1 秒 2.6M rows 2.6M rows 1.2 s
1 分钟 2.6M rows 43K rows 450 ms
1 小时 2.6M rows 720 rows 320 ms
1 天 2.6M rows 30 rows 280 ms

结论: Polars LazyFrame 优化后,即使百万行数据,聚合查询仍可在 100ms 内完成。


网络性能

1. HTTP API 性能

测试工具: Apache Bench (ab)

测试命令:

ab -n 100000 -c 100 -p order.json -T application/json \
   http://localhost:8000/api/order/submit

测试结果:

端点 并发数 吞吐量 (req/s) P50 延迟 P99 延迟
GET /health 100 82,000 1.2 ms 3.5 ms
GET /api/account/:id 100 58,000 1.7 ms 4.8 ms
POST /api/order/submit 100 48,000 2.1 ms 6.2 ms
POST /api/order/cancel 100 52,000 1.9 ms 5.5 ms
GET /api/monitoring/system 100 35,000 2.8 ms 8.5 ms

连接复用性能:

连接方式 吞吐量 (req/s) 性能提升
短连接 12,000 1x
Keep-Alive 48,000 4x
HTTP/2 65,000 5.4x

2. WebSocket 性能

连接建立延迟:

并发连接数 P50 延迟 P95 延迟 P99 延迟
100 8 ms 15 ms 22 ms
1,000 12 ms 25 ms 38 ms
10,000 18 ms 35 ms 52 ms

消息推送延迟 (peek_message → rtn_data):

订阅者数量 消息大小 P50 延迟 P95 延迟 P99 延迟
1 256 B 0.15 ms 0.32 ms 0.48 ms
10 256 B 0.22 ms 0.45 ms 0.68 ms
100 256 B 0.35 ms 0.72 ms 1.05 ms
1,000 256 B 0.52 ms 0.95 ms 1.38 ms
10,000 256 B 0.88 ms 1.52 ms 2.15 ms

批量推送优化 (100 条/批):

优化前 优化后 性能提升
100 次 send() 1 次 send() 15x
P99 = 15 ms P99 = 1 ms 延迟降低 93%

3. 通知系统性能

Notification 序列化性能:

格式 序列化延迟 反序列化延迟 序列化大小
JSON 1,200 ns 2,500 ns 350 bytes
rkyv 300 ns 20 ns 285 bytes
提升 4x 125x 19% 减少

NotificationBroker 吞吐量:

优先级 吞吐量 (msg/s) 延迟
P0 (紧急) 500K < 1 μs
P1 (高) 450K < 2 μs
P2 (普通) 400K < 5 μs
P3 (低) 350K < 10 μs

背压控制效果:

队列积压阈值: 500 消息

积压 < 500: 全部推送(P0-P3)
积压 500-1000: 丢弃 P3
积压 1000-2000: 丢弃 P2-P3
积压 > 2000: 仅保留 P0

内存峰值: 2000 × 300 bytes ≈ 600 KB

端到端延迟

完整交易流程延迟分析

场景: 用户提交订单 → 撮合成交 → 收到通知

延迟分解:

步骤 组件 延迟 累计延迟
1 HTTP 接收 0.05 ms 0.05 ms
2 参数验证 0.02 ms 0.07 ms
3 预交易检查 0.15 ms 0.22 ms
4 订单路由 0.08 ms 0.30 ms
5 撮合引擎 0.08 ms 0.38 ms
6 成交回调 0.05 ms 0.43 ms
7 通知序列化 0.0003 ms 0.4303 ms
8 WebSocket 推送 0.30 ms 0.73 ms
9 WAL 写入 (异步) 12 ms 12.73 ms (后台)

端到端延迟:

  • 关键路径 (下单 → 收到通知): P99 = 0.95 ms
  • 包含持久化 (WAL 完成): P99 = 15 ms

延迟优化路径:

原始延迟: 2.5 ms
  ↓ 使用 parking_lot::RwLock (-0.5 ms)
  ↓ 使用 rkyv 序列化 (-0.8 ms)
  ↓ 批量 WebSocket 推送 (-0.5 ms)
最终延迟: 0.7 ms (72% 降低)

并发性能

1. 并发账户处理

测试场景: 多个账户同时交易

测试结果:

账户数 并发订单/秒 CPU 占用 内存占用
100 145K 25% 512 MB
1,000 142K 45% 1.2 GB
10,000 138K 75% 4.5 GB
50,000 125K 95% 18 GB

结论: 支持 10K+ 并发账户,吞吐量仅下降 5%。


2. 锁竞争分析

DashMap 性能 (vs std::HashMap + RwLock):

操作 DashMap HashMap+RwLock 性能提升
读取 (10 线程) 850K ops/s 320K ops/s 2.7x
写入 (10 线程) 480K ops/s 85K ops/s 5.6x
混合 (90% 读) 780K ops/s 280K ops/s 2.8x

parking_lot::RwLock 性能 (vs std::sync::RwLock):

操作 parking_lot std::sync 性能提升
读锁获取 15 ns 45 ns 3x
写锁获取 25 ns 78 ns 3.1x
读写混合 18 ns 52 ns 2.9x

3. 线程扩展性

订单吞吐量 vs 线程数:

线程数 吞吐量 (orders/s) 加速比 效率
1 165K 1.0x 100%
2 315K 1.9x 95%
4 585K 3.5x 88%
8 1.05M 6.4x 80%
16 1.75M 10.6x 66%
32 2.25M 13.6x 43%

最佳线程数: CPU 核心数 × 1.5 (本机 16 核 → 24 线程)


压力测试

1. 持续负载测试

测试场景: 连续 24 小时高负载运行

配置:

  • 并发账户: 10,000
  • 订单提交速率: 50K orders/s
  • WebSocket 连接: 5,000

测试结果:

时间段 吞吐量 P99 延迟 内存占用 错误率
0-6h 50.2K/s 0.92 ms 4.2 GB 0.001%
6-12h 50.1K/s 0.95 ms 4.5 GB 0.002%
12-18h 49.8K/s 0.98 ms 4.8 GB 0.003%
18-24h 49.5K/s 1.02 ms 5.1 GB 0.005%

观察:

  • 吞吐量稳定 (波动 < 2%)
  • 内存缓慢增长 (4.2 GB → 5.1 GB)
  • 错误率极低 (< 0.01%)
  • 无崩溃或重启

2. 峰值负载测试

测试场景: 短时间极限负载

测试方法: 1 分钟内提交 1000 万订单

测试结果:

时间 (秒) 订单数 吞吐量 P99 延迟 CPU 内存
0-10 1.8M 180K/s 1.2 ms 95% 5.2 GB
10-20 1.75M 175K/s 1.5 ms 98% 6.5 GB
20-30 1.72M 172K/s 1.8 ms 98% 7.8 GB
30-40 1.68M 168K/s 2.2 ms 99% 9.2 GB
40-50 1.65M 165K/s 2.8 ms 99% 10.5 GB
50-60 1.62M 162K/s 3.5 ms 99% 11.8 GB
总计 10.2M 平均 170K/s - - -

结论: 峰值负载下吞吐量略有下降(180K → 162K),但仍远超目标(100K)。


3. 故障恢复测试

测试场景: 强制终止进程后重启

测试方法:

  1. 正常运行 1 小时(写入 100K 订单)
  2. 强制 kill -9 进程
  3. 立即重启
  4. 验证数据完整性

恢复时间:

WAL 大小 记录数 恢复时间 数据完整性
128 MB 100K 2.5 s 100%
512 MB 400K 9.8 s 100%
1 GB 800K 18.5 s 100%
4 GB 3.2M 72 s 100%

结论: WAL 回放速度约 45K records/s,数据零丢失。


性能优化建议

1. 编译优化

Cargo.toml:

[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
panic = "abort"

性能提升: 15-25%


2. 硬件优化

推荐配置:

  • CPU: 高主频 (> 3.5GHz),多核 (16+ 核)
  • 内存: 32+ GB,DDR4 3200MHz+
  • 存储: NVMe SSD (读写 > 3000 MB/s)
  • 网络: 10 Gbps Ethernet

SSD vs HDD:

  • WAL 写入延迟: 50ms (SSD) vs 200ms (HDD) - 4x 提升
  • SSTable 读取: 0.05ms (SSD) vs 10ms (HDD) - 200x 提升

3. 系统调优

Linux 内核参数:

# 增加最大文件描述符
ulimit -n 1048576

# 增加 TCP 连接队列
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=8192

# 启用 TCP Fast Open
sysctl -w net.ipv4.tcp_fastopen=3

# 增加网络缓冲区
sysctl -w net.core.rmem_max=134217728
sysctl -w net.core.wmem_max=134217728

4. 应用优化

批量操作:

// 不好: 单条插入
for order in orders {
    wal.append_record(order);  // 100 次磁盘 I/O
}

// 好: 批量插入
wal.append_batch(&orders);  // 1 次磁盘 I/O (100x 提升)

连接池:

// HTTP 客户端使用连接池
let client = reqwest::Client::builder()
    .pool_max_idle_per_host(100)
    .build()?;

异步 I/O:

// 不好: 同步写入 WAL 阻塞撮合
engine.match_order();
wal.append_record().wait();  // 阻塞 10ms

// 好: 异步写入 WAL
engine.match_order();
tokio::spawn(async move {
    wal.append_record().await;  // 非阻塞
});

5. 监控和调优

启用性能监控:

# Prometheus 指标
curl http://localhost:8000/metrics

# 关键指标
# - qaexchange_order_latency_seconds (histogram)
# - qaexchange_matching_duration_seconds (histogram)
# - qaexchange_wal_write_duration_seconds (histogram)

使用 flamegraph 分析热点:

cargo install flamegraph
sudo flamegraph --bin qaexchange-server
# 查看 flamegraph.svg 找出性能瓶颈

测试方法

1. 吞吐量测试

使用 Apache Bench:

# 创建测试数据
cat > order.json <<EOF
{
  "user_id": "user123",
  "order_id": "order001",
  "instrument_id": "SHFE.cu2501",
  "direction": "BUY",
  "offset": "OPEN",
  "volume": 1,
  "price_type": "LIMIT",
  "limit_price": 50000
}
EOF

# 运行测试
ab -n 100000 -c 100 -p order.json -T application/json \
   http://localhost:8000/api/order/submit

# 分析结果
# - Requests per second: 吞吐量
# - Time per request: 平均延迟
# - Percentage of the requests served within a certain time: 延迟分布

2. 延迟测试

使用 Criterion 基准测试:

benches/matching_bench.rs:

use criterion::{black_box, criterion_group, criterion_main, Criterion};

fn bench_matching(c: &mut Criterion) {
    let engine = create_test_engine();

    c.bench_function("matching", |b| {
        b.iter(|| {
            engine.submit_order(black_box(order.clone()))
        })
    });
}

criterion_group!(benches, bench_matching);
criterion_main!(benches);

运行:

cargo bench
# 查看 target/criterion/matching/report/index.html

3. 压力测试

使用 Gatling:

simulations/OrderSubmission.scala:

import io.gatling.core.Predef._
import io.gatling.http.Predef._

class OrderSubmission extends Simulation {
  val httpProtocol = http.baseUrl("http://localhost:8000")

  val scn = scenario("Submit Orders")
    .exec(http("submit order")
      .post("/api/order/submit")
      .header("Content-Type", "application/json")
      .body(StringBody("""{"user_id":"user123",...}"""))
      .check(status.is(200))
    )

  setUp(scn.inject(
    constantUsersPerSec(1000) during (60 seconds)
  )).protocols(httpProtocol)
}

运行:

gatling.sh -sf simulations/ -s OrderSubmission

4. 内存泄漏检测

使用 Valgrind:

valgrind --leak-check=full --show-leak-kinds=all \
  target/debug/qaexchange-server

使用 heaptrack:

heaptrack target/release/qaexchange-server
heaptrack_gui heaptrack.qaexchange-server.*.gz

性能基准总结

✅ 已达到目标

指标 目标 实际 状态
订单吞吐量 > 100K/s 150K/s ✅ +50%
撮合延迟 P99 < 100μs 85μs
WAL 写入 P99 < 50ms 35ms
MemTable 写入 P99 < 10μs 7μs
并发账户 > 10,000 15,000 ✅ +50%

📊 性能亮点

  1. 零拷贝优化: rkyv 反序列化 125x vs JSON
  2. 批量优化: WAL 批量写入 600x 提升
  3. Bloom Filter: SSTable 查询延迟降低 30-40%
  4. 并发优化: DashMap 读写 2.7-5.6x vs 标准库
  5. 端到端延迟: 下单到通知 P99 < 1ms

🎯 后续优化方向

  1. SIMD 优化: 使用 SIMD 加速 Bloom Filter 哈希计算
  2. 分布式扩展: 实现 Master-Slave 网络层(gRPC)
  3. 块索引: SSTable 块级索引减少读放大
  4. 自适应 Compaction: 根据负载动态调整 Compaction 策略


可观测性开销 (Phase 12) ✨ NEW

OpenTelemetry 追踪开销

操作 开销 说明
Span 创建 ~80 ns info_span! 宏
Span 结束 ~50 ns 自动 drop
属性添加 ~20 ns/属性 span.record()
批量导出 (100 spans) < 1 ms 异步非阻塞

Prometheus 指标开销

操作 开销
Counter.inc() ~10 ns
Gauge.set() ~10 ns
Histogram.observe() ~50 ns
指标采集 (/metrics) ~5 ms (1K 指标)

日志记录开销

级别 开销 (启用) 开销 (禁用)
ERROR ~500 ns ~5 ns
INFO ~400 ns ~5 ns
DEBUG ~400 ns ~5 ns

安全层性能 (Phase 13) ✨ NEW

TLS 性能

操作 延迟
证书生成 (RSA 2048) ~50 ms
TLS 握手 ~5 ms
TLS 记录加密 ~0.5 μs/KB
mTLS 额外开销 (首次) +8 ms

SIMD 加速

操作 Scalar AVX2 加速比
find_best_price (1K) 800 ns 150 ns 5.3x
sum_volumes (1K) 500 ns 100 ns 5x
filter_by_price (1K) 1.2 μs 200 ns 6x
crc32 (4KB) 2 μs 400 ns 5x

Block Index 性能

操作 延迟 复杂度
块查找 ~500 ns O(log n)
时间范围查询 ~1 μs O(log n + k)
内存开销/entry 48 bytes O(n)

版本: v1.1.0 测试日期: 2025-12-18 测试人员: @yutiansut @quantaxis


返回文档中心 | 术语表 | 常见问题