测试工具选型:wrk、JMeter、Locust、自定义C++客户端、市场数据回放工具

做性能基准测试,选对工具等于成功了一半。

我见过不少团队,上来就用JMeter压交易系统,结果发现连网关都打不透。不是工具不好,是没选对场景。今天咱们就聊聊,交易系统测试到底该用哪些工具,各自适合什么场景。

先画张图,理清思路

下面这张图,是我个人习惯的测试工具选型决策流程。你想想看,不同场景对工具的要求完全不一样。

测试工具选型决策树 交易系统性能测试 协议层/网关测试 业务逻辑/风控测试 wrk(HTTP/WebSocket) 自定义C++客户端(FIX/二进制) JMeter(复杂业务流程) Locust(分布式压测) 特殊场景:市场数据回放 回放历史行情数据,验证策略与系统稳定性 选型核心:协议层追求极致性能,业务层关注场景覆盖,特殊场景需要真实数据

wrk:轻量级协议压测利器

wrk是我个人最常用的工具之一。它基于Reactor模式,用C写的,性能极高。

说白了,wrk就干一件事:用最少的资源,打出最大的请求量。

适用场景:

  • HTTP/HTTPS接口的基准测试
  • WebSocket连接的性能摸底
  • 网关层的极限吞吐测试

举个例子,压测一个交易网关的HTTP接口:

wrk -t12 -c400 -d30s --latency http://trade-gateway:8080/api/v1/order

这条命令的意思是:12个线程,400个并发连接,持续30秒。输出结果里,我重点关注两个指标:Requests/secLatency分布

我的经验:wrk的Lua脚本扩展能力很强。我曾经用它模拟了一个简单的订单流——先登录获取token,再发单,最后查成交。虽然不如JMeter灵活,但性能开销极低,适合做纯协议层的压测。

JMeter:复杂业务流程的首选

JMeter的好处是啥?图形化,插件多,上手快。

但我要泼盆冷水——别拿JMeter去压网关。为什么?因为JMeter本身是Java写的,线程模型太重了。我曾经试过用JMeter压一个简单的HTTP接口,200并发就把客户端CPU吃满了,而wrk跑到2000并发还游刃有余。

避坑指南:我曾经在一个项目中,团队用JMeter压测风控系统,结果压测结果忽高忽低。排查了半天,发现是JMeter的聚合报告采样间隔设置不合理,导致数据失真。记住:JMeter适合做功能验证型压测,不适合做极限性能摸底

JMeter的强项在于:

  • 支持复杂的业务流编排(登录→下单→撤单→查询)
  • 丰富的断言和监听器
  • 分布式压测(虽然配置起来有点麻烦)

Locust:Python党的分布式压测方案

Locust用Python写测试脚本,这点很讨喜。你想想看,量化团队里Python用得最多,用Locust可以快速上手。

一个简单的Locust脚本长这样:

from locust import HttpUser, task, between

class TradeUser(HttpUser):
    wait_time = between(0.1, 0.5)

    @task
    def place_order(self):
        self.client.post("/api/v1/order", json={
            "symbol": "BTCUSDT",
            "side": "BUY",
            "price": 50000,
            "quantity": 0.1
        })

Locust的Web UI做得不错,可以实时看到RPS、响应时间、失败率。而且它天生支持分布式——启动一个master,再起几个worker,就能轻松扩展到上千并发。

适用场景:

  • 需要快速验证业务逻辑的场景
  • 团队以Python为主的量化团队
  • 需要分布式压测但不想折腾JMeter集群的

自定义C++测试客户端:追求极致性能

说到这个,我得认真讲讲。

交易系统里,很多协议不是HTTP,而是FIX协议或者自研的二进制协议。这时候,wrk、JMeter、Locust全都用不上。怎么办?自己写。

我习惯用C++写自定义压测客户端,原因很简单:

  • 可以精确控制每个数据包的发送时机
  • 零拷贝、内存池、无锁队列,这些优化手段都能用上
  • 能模拟真实的交易行为,比如订单簿快照、增量更新

一个简单的FIX协议压测客户端框架:

class FixClient {
public:
    void connect(const std::string& host, int port);
    void send_order(const Order& order);
    void on_message(const FixMessage& msg);
    
private:
    int sock_fd_;
    char send_buf_[4096];
    char recv_buf_[4096];
    // 内存池、连接池等优化
};

我的经验:写自定义客户端时,一定要注意客户端本身不能成为瓶颈。我曾经遇到过,压测结果上不去,查了半天发现是客户端单线程处理不过来。后来改成多线程+无锁队列,性能直接翻了3倍。

市场数据回放工具:最接近真实场景的测试

前面说的几种工具,都是模拟请求。但交易系统有个特殊的地方——市场数据是实时变化的

你想想看,行情快照、逐笔成交、订单簿变化,这些数据流对系统的影响,光靠模拟请求是测不出来的。

市场数据回放工具,说白了就是把历史行情数据录下来,然后按时间顺序重新播放给系统。这样系统就像在真实环境中运行一样。

我常用的回放方案:

  • 从交易所获取历史行情数据(Tick级或毫秒级)
  • 用C++或Go写一个回放引擎,控制数据发送的时序
  • 在回放过程中,同时注入模拟的交易请求

避坑指南:我曾经在回放测试中踩过一个坑——回放速度太快,导致系统处理不过来,但实际交易中并不会出现这么极端的情况。后来我加了一个时间缩放因子,可以控制回放速度是1倍、2倍还是0.5倍。这样既能测试系统的极限,又能模拟真实场景。

工具选型总结

工具 核心优势 适用场景 注意事项
wrk 极致性能,资源占用低 HTTP/WebSocket协议层压测 不支持复杂业务逻辑
JMeter 图形化,插件丰富 复杂业务流程验证 客户端本身可能成为瓶颈
Locust Python脚本,分布式友好 快速原型验证 性能不如wrk和C++客户端
自定义C++客户端 完全可控,极致性能 FIX/二进制协议压测 开发成本高
市场数据回放工具 最接近真实场景 行情驱动型系统测试 需要历史数据源

最后说一句:没有银弹。每个工具都有自己的定位,关键是你得清楚自己要测什么。协议层用wrk,业务层用JMeter或Locust,特殊协议自己写客户端,真实场景用回放工具。这样搭配起来,基本能覆盖交易系统性能测试的方方面面。


专注资料整理