核心性能指标:延迟、吞吐量、抖动、持久性、一致性
做低延迟交易系统,说白了就是跟时间赛跑。我经常跟团队说,你设计的系统好不好,不是看代码多漂亮,而是看这几个数字能不能打。今天咱们就聊聊这五个核心指标——延迟、吞吐量、抖动、持久性、一致性,以及它们之间那些让人头疼的权衡。
延迟:最直观的敌人
延迟就是一笔订单从发出到确认的时间。我习惯把它拆成三部分:网络延迟、处理延迟、排队延迟。
- 网络延迟:光纤传输、交换机转发,物理定律没法突破
- 处理延迟:CPU算订单、内存读写、磁盘IO
- 排队延迟:请求在队列里等着被处理的时间
我在项目中遇到过最夸张的情况——某次行情数据从交易所到我们的策略服务器,网络延迟只有50微秒,但排队延迟硬生生拖到了200微秒。为什么?因为队列长度没控制好。你想想看,一个队列里塞了上千个请求,每个请求处理1微秒,那最后一个就得等1毫秒。这在高频交易里,黄花菜都凉了。
核心观点:延迟优化不是只盯着处理时间,排队延迟往往才是大头。
吞吐量:能扛多少活
吞吐量就是单位时间内能处理多少笔交易。有人觉得吞吐量越高越好,其实不然。我见过一个系统,吞吐量标称每秒10万笔,但延迟飙到了50毫秒。这种系统做批量结算还行,做高频交易?门都没有。
吞吐量和延迟的关系,有点像高速公路。车少的时候,每辆车跑得飞快(延迟低)。车一多,大家都堵在路上(延迟高)。但如果你把车道加宽(提升吞吐量),车流就能保持顺畅。
我的经验:设计时先定延迟目标,再算吞吐量。别反过来,否则你会陷入「吞吐量上去了,延迟下不来」的尴尬。
抖动:最隐蔽的杀手
抖动就是延迟的波动。平均延迟1毫秒,但偶尔跳到10毫秒,这种系统最要命。为什么?因为交易策略是基于「稳定延迟」来设计的。突然来一下抖动,策略可能就误判了行情。
我曾经排查过一个抖动问题,查了三天才发现是JVM的GC在作祟。平时GC只停几毫秒,但有一次Full GC停了200毫秒。嗯,那笔交易直接滑点滑到姥姥家去了。
抖动的来源通常有这几个:
- GC暂停(Java系系统常见)
- 操作系统调度(线程被抢占了CPU)
- 磁盘IO抖动(突然写日志)
- 网络重传(丢包了)
避坑指南:我曾经以为只要平均延迟低就行,结果被抖动坑惨了。现在我的原则是——宁可平均延迟高10%,也要把抖动压到最低。
持久性:数据不能丢
持久性就是数据写入后,不会因为系统崩溃而丢失。交易日志必须持久化,这是底线。但持久化是有代价的——每次写磁盘都慢。
常见的持久化策略:
- 同步刷盘:每次写入都等磁盘确认,延迟高但最安全
- 异步刷盘:先写内存缓冲区,后台批量刷盘,延迟低但可能丢数据
- 组提交:攒一批再刷盘,折中方案
我建议交易日志用同步刷盘,但配合内存映射文件(mmap)来降低延迟。具体怎么做?看下面这个伪代码:
// 内存映射文件写入示例
MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, FILE_SIZE);
// 写入日志条目
buffer.putLong(timestamp);
buffer.putInt(orderId);
buffer.put(orderData);
// 强制刷盘(只刷这一页)
buffer.force();
这样写的好处是,操作系统帮你管理内存和磁盘的同步,延迟比传统FileChannel.write低一个数量级。
一致性:日志不能乱
一致性指的是多个副本之间的数据是否相同。在交易系统里,日志的一致性尤其重要——如果主库和备库的日志对不上,恢复时就会出大问题。
一致性模型分几种:
| 模型 | 说明 | 适用场景 |
|---|---|---|
| 强一致性 | 所有副本实时同步 | 交易核心日志 |
| 最终一致性 | 允许短暂不一致 | 非关键日志 |
| 因果一致性 | 有因果关系的操作必须有序 | 事件溯源 |
交易日志我建议用强一致性。为什么?因为一旦发生故障恢复,日志不一致会导致订单状态错乱。你想想看,一个订单在A库显示已成交,在B库显示未成交,你信谁?
权衡关系:鱼和熊掌
这五个指标没法同时做到最优。我画了一张图,帮你理清它们之间的关系:
从这张图你能看出来,每个指标都跟相邻指标有冲突。比如:
- 延迟 vs 吞吐量:想延迟低,就得减少排队,但吞吐量就上不去
- 持久性 vs 延迟:每次刷盘都增加延迟,但数据更安全
- 一致性 vs 抖动:强一致性需要同步复制,网络波动会引入抖动
我个人的做法是:先定延迟和抖动的上限,再在这个约束下最大化吞吐量。持久性和一致性则根据业务场景来——核心交易日志用强一致+同步刷盘,非关键日志用最终一致+异步刷盘。
实战建议:别追求所有指标都最优。你只需要找到那个「够用」的平衡点。比如你的策略要求延迟<1ms,抖动<100μs,那就围绕这个目标去设计,其他指标能达标就行。
最后说一句,这些指标不是静态的。系统上线后,你得持续监控它们。我习惯在日志系统里埋点,实时采集延迟和抖动的P50、P99、P999值。一旦发现P99抖动超过阈值,立刻报警。嗯,这才是做低延迟系统该有的态度。