高频交易系统中的大吞吐量订单发送机制
·1 min
1. 需求背景 #
在高频交易系统中,我们面临一个典型场景:需要同时处理三个关联订单(三角套利)。这些订单必须几乎同时发出以确保套利的有效性。
关键挑战:
- 订单必须同时或几乎同时发出
- 系统需要处理高并发的订单组
- 需要保证订单处理的稳定性和可靠性
2. 当前使用的两种处理订单的机制 #
- 无锁队列机制
- 订单生成后进入一个无锁队列
- 多个线程从队列中取订单进行处理
- 订单的发送通过RestClient进行,RestClient负责管理HTTP连接池并发送请求
- 分片机制
- 订单生成后根据某种规则分配到不同的分片
- 每个分片由固定的线程处理
- 同一组的订单被分配到同一个分片,确保组内订单的处理一致性
- RestClient同样负责订单的发送
class OrderShard {
private:
struct OrderGroup {
uint64_t groupId;
uint64_t timestamp;
std::vector<Order> orders;
};
std::queue<OrderGroup> orderQueue_;
std::mutex mutex_;
std::condition_variable cv_;
RestClient restClient_;
public:
void addOrderGroup(OrderGroup group) {
{
std::lock_guard<std::mutex> lock(mutex_);
orderQueue_.push(std::move(group));
}
cv_.notify_one();
}
void processOrders() {
while (running_) {
OrderGroup group;
{
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this] {
return !orderQueue_.empty() || !running_;
});
if (!running_) break;
group = std::move(orderQueue_.front());
orderQueue_.pop();
}
// 批量发送同组订单
sendOrderGroup(group);
}
}
private:
void sendOrderGroup(const OrderGroup& group) {
// 使用同一个连接发送组内所有订单
auto conn = restClient_.getConnection();
for (const auto& order : group.orders) {
conn->sendOrder(order);
}
}
};
3. 两种机制的执行结果分析 #
- 无锁队列机制
- 日志显示组内订单的发送时间差较大,通常在180-220ms之间
- 存在较大的延迟波动,部分组的最大时间差超过1000ms
总订单组数: 164
存在时间差的组数: 161
最大时间差: 2961.000ms
平均时间差: 308.851ms
分片机制
- 日志显示组内订单的发送时间差非常小,基本在0-1ms之间
- 订单几乎同时发出,延迟波动很小
总订单组数: 416 存在时间差的组数: 166 最大时间差: 425.000ms 平均时间差: 56.991ms
4. 机制差异分析 #
- 无锁队列机制
- 所有订单进入同一个队列
- 多个线程从同一队列取任务,即使是无锁的,仍然存在竞争
- 同一组的三个订单可能被不同线程处理,导致时间差
- 线程调度的不确定性导致组内订单的发送时间不一致
- 分片机制
- 通过分片将同组订单分配到同一线程,避免了线程间的竞争
- 固定线程处理同一分片,确保了组内订单的处理顺序和时间一致性
5. 适合需求的最佳方案 #
- 分片机制
- 理由:分片机制能够确保同组订单的处理一致性,满足几乎同时发出的需求
- 通过减少线程竞争和调度不确定性,分片机制提供了更稳定的性能
6. 最佳方案的优化方向 #
- 优化分片策略
- 根据订单特性优化分片规则,进一步提高处理效率
- 调整线程池配置
- 根据系统负载动态调整线程池大小,确保资源的合理利用
- 优化RestClient连接池
- 根据请求并发量调整连接池大小,确保请求的快速发送
- 监控和调优
- 持续监控系统性能,识别瓶颈并进行调优
- 使用性能分析工具识别和优化关键路径