问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

揭秘Jane Street低延迟系统的优化技巧——减少系统抖动

创作时间:
作者:
@小白创作中心

揭秘Jane Street低延迟系统的优化技巧——减少系统抖动

引用
CSDN
1.
https://blog.csdn.net/h1453586413/article/details/144054257

在高频交易等对延迟敏感的领域,保持稳定且低的抖动对于降低风险至关重要。Jane Street的软件工程师Tudor Brindus分享了如何通过减少系统抖动来优化低延迟系统,从软件层面的参数调整到微架构级别的优化,每一步都需要对系统有深刻的理解。

一个玩具示例:在机器内的多核间分发消息

Tudor以一个简单的内存乒乓应用为案例,详细讲解了如何识别并解决由Linux内核和微架构条件引起的常见抖动源。

引入环形缓冲区

Tudor介绍了环形缓冲区(Ring Buffer)的概念,这是一个具有固定大小单元的数组,当数据到达数组末尾时会重新循环到起点。他解释道,通过在机器上的两个进程之间建立环形缓冲区,可以实现高效的数据传递。

在他的乒乓示例中,有两个进程:发球者(Pinger)接球者(Ponger),以及两个环形缓冲区,用于在这两个进程之间传递数据。他们通过在缓冲区中写入和读取整数,实现数据的往返传输。Tudor用一个发球者(Pinger)和接球者(Ponger)的案例演示了环形缓冲区的使用:

  1. 发球者在发球者到接球者的环形缓冲区的第一个单元中写入整数1。
  2. 接球者读取该值1,加1得到2,然后将其写回接球者到发球者的环形缓冲区。
  3. 发球者读取回来的值,继续加1得到3,然后写入环形缓冲区的下一个单元。
  4. 当到达环形缓冲区的末尾时,循环重新开始。

他通过OCaml代码展示了这一逻辑,并讨论了延迟的测量方法——通过记录发球者写入值和接球者完成处理的时间戳,计算延迟T2 - T1。

let ping_pong consumer producer =
  while true do
    let read_buf = Ringbuf.Consumer.poll consumer in
    if not (Iobuf.is_empty read_buf)
    then (
      let data = Iobuf.Consume.int64_le_trunc read_buf in
      let new_data = data + 1 in
      let write_buf = Ringbuf.Producer.write_buf producer in
      Iobuf.Fill.int64_le write_buf new_data;
      Ringbuf.Producer.finish_write producer;
      Ringbuf.Consumer.finish_poll consumer
    )
  done
;;

基准测试设置

  • 典型的英特尔服务器
  • 第二代英特尔至强金牌CPU @ 3.6 GHz(Cascade Lake)
  • 2666 MHz DDR4内存
  • Linux 3.10

基准测试设置

基准测试的初步结果表明,抖动可能高达16微秒。这引出了一个重要问题:抖动的来源是什么?

优化前的初始尝试:虚拟化环境与裸机硬件

Tudor在优化过程中,首先比较了虚拟化环境(Virtualized Environment)和裸机硬件(Bare Metal Hardware)的性能差异,结果显示裸机硬件在延迟和抖动控制上具有明显优势。

Try 1: 虚拟化环境(Virtualized Environment)

在虚拟机(VM)中运行测试时,延迟测量的结果显示:

  • 延迟:抖动范围高达16微秒。
  • 特征:
  • 存在大量噪声,尤其在延迟的长尾部分(如1微秒以上)。
  • 可能是由于邻居噪声问题(Noisy Neighbor Problem),即同一物理主机上运行的其他虚拟机占用了CPU周期。
  • 还可能存在虚拟机额外开销,例如上下文切换和虚拟化相关的中断处理。

问题分析:
虚拟机引入了大量不可控的延迟,尤其是尾部延迟。对于高性能低延迟系统来说,这种不确定性会极大影响稳定性。

Try 2: 裸机硬件(Bare Metal Hardware)

通过将相同的测试程序从虚拟化环境切换到裸机硬件(直接在物理主机上运行)后,结果显著改善:

  • 延迟:从637纳秒降至223纳秒。
  • 特征:
  • 抖动减少了大部分噪声。
  • 延迟曲线更加平滑,尤其是尾部延迟显著改善。

优化分析:

  1. 无虚拟化开销:裸机硬件直接运行程序,避免了虚拟机带来的中断处理和邻居噪声问题。
  2. 更高的性能确定性:裸机硬件的延迟更可预测,减少了不确定性。

总结:虚拟化与裸机的对比
Tudor强调,如果性能和延迟确定性非常重要,应优先选择裸机硬件而非虚拟机环境。虽然裸机硬件可能会增加基础设施成本,但其在性能上的优势为高性能低延迟系统带来了更稳定和可靠的运行环境。

然而,在裸机环境下仍然存在一些延迟峰值(例如1微秒的延迟),这需要进一步优化。

深入识别并消除抖动源

虚拟化环境的影响

Tudor指出,由于在虚拟机(VM)上运行程序,可能会遇到邻居噪声问题(Noisy Neighbor Problem),即共享主机的其他用户占用了资源。此外,虚拟机还可能带来额外的开销。

他建议使用裸机硬件(Bare Metal Hardware)来避免这些问题。通过简单地切换到裸机运行,延迟从637纳秒降至223纳秒,同时大幅减少了噪声。

然而,在裸机环境下仍然存在一些延迟峰值(例如1微秒的延迟),这需要进一步优化。

网络中断导致的抖动

面对即使在裸机上,系统仍然存在抖动的问题,Tudor使用了MagicTrace。MagicTrace这个工具可以生成包含调用栈深度和时间轴的图表,帮助定位抖动的来源。Tudor使用MagicTrace分析延迟峰值后发现,网络活动会通过中断机制干扰CPU的正常运行,导致系统抖动。这是因为当网络设备接收到数据包时,会通过中断通知CPU,这些中断可能会影响正在运行的应用程序。

MagicTrace
Y轴:调用栈深度(Call Stack Depth)
X轴:表示时间(Time)

网络活动
CPU中断示意图

解决方法:

  • 使用内核参数isolcpus隔离特定的CPU核心,将特定的CPU核心隔离出来,避免它们处理网络中断。
  • 将需要运行的进程绑定到隔离的CPU核心上(例如通过taskset命令)。

优化效果:
通过这一调整,系统延迟从223纳秒降低到了194纳秒,同时抖动显著减少。

隔离CPU后的结果

定时器中断的影响

进一步的分析显示,本地定时器中断也是抖动的来源。默认情况下,内核每秒钟会触发1000次定时器中断,用于调度和统计。通过设置nohz_full参数,可以关闭这些定时器中断,从而将延迟降低到170纳秒。

定时器中断

解决方法:

  • 使用内核参数nohz_full关闭定时器中断,使内核在特定CPU核心上尽量减少中断频率。

优化效果:
这一调整将定时器中断的频率从每秒一千次减少到每秒一次,使延迟进一步降低了24纳秒。

处理器频率调整的影响

Turbo Boost等处理器频率调整技术会引入频率转换的延迟,导致抖动。禁用Turbo Boost可以提高延迟的一致性,尽管这可能会略微降低平均性能。在实验中,禁用后系统的延迟稳定在了164纳秒。

禁用Turbo Boost的结果

微架构级别的优化

即使经过上述优化,仍然存在一些抖动。Tudor指出,这可能与推测执行(speculative execution)相关。在高频循环中,CPU会猜测下一个操作,从而导致错误推测(bad speculation),引入性能开销。

推测执行(speculative execution)

推测执行(speculative execution)

通过在循环中加入pause指令,可以提示处理器进行优化,减少错误推测。对于OCaml代码,需要在编译器中引入对应的内联函数(intrinsic)。这一优化使延迟进一步降低到了163纳秒。

关于推测执行的代码示例

let ping_pong consumer producer =
  while true do
    let read_buf = Ringbuf.Consumer.poll consumer in
    if not (Iobuf.is_empty read_buf)
    then (
      let data = Iobuf.Consume.int64_le_trunc read_buf in
      let new_data = data + 1 in
      let write_buf = Ringbuf.Producer.write_buf producer in
      Iobuf.Fill.int64_le write_buf new_data;
      Ringbuf.Producer.finish_write producer;
      Ringbuf.Consumer.finish_poll consumer
    )
  done
;;

硬件选择的重要性

最后,Tudor还提到了硬件本身对性能的影响。使用更高频率的CPU和更快的内存可以显著提高性能。然而,过度超频可能导致系统不稳定,甚至出现内存错误。

关键总结

通过这一系列优化,Tudor将系统的延迟从最初的637纳秒降低到了163纳秒,抖动也大大减少。主要的经验教训包括:

  • 避免在虚拟化环境中运行对延迟敏感的应用。
  • 深入理解系统架构,针对性地进行优化。
  • 硬件选择至关重要,但需要平衡性能和稳定性。
  • 持续监测系统性能,及时发现并解决问题。

总结

Tudor的本次分享深入揭示了在低延迟系统中减少抖动的各种方法。从软件层面的参数调整到微架构级别的优化,每一步都需要对系统有深刻的理解。对于从事高频交易、实时系统或任何对延迟敏感的领域的工程师,这些经验都具有重要的参考价值。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号