我们将在后面的章节中了解到,高频与交易策略的类型和您交易的资产以及您交易的交易所的能力有关。实现 100 微秒的即时交易延迟需要仔细的编程和对底层硬件的深入了解。您需要编写最好的代码来利用 CPU 及其内存架构,并最大限度地减少 I/O 操作的开销。本章的重点是获得基线(就我们应该拥有的硬件和操作系统而言),以便拥有一个能够实现良好性能的自动交易系统。后面的章节将帮助我们完善这一点,应用不同的优化技术来改善交易系统的延迟,使我们的延迟甚至低于 10 微秒。
假设您想深入了解现代计算机系统体系结构的工作原理。在这种情况下,John Hennessy 和 David Patterson 合着的经典著作《计算机体系结构:定量方法》对此进行了详细解释,并开发了统计模型以帮助理解性能权衡。在本章中,我们将重点关注高频交易系统运行所需的部分。下一节将介绍该系统所使用的机器的硬件。
了解HFT系统
很容易想到您可能需要一些专门的计算机硬件来执行任何低延迟交易策略。事实并非如此——大多数硬件都是普通的现成硬件。在大多数情况下,如何配置硬件更为重要。图 4.1 显示了一个主 CPU,代表了 HFT 系统的开发人员如何考虑 CPU 的架构。
图4.1——主CPU
正如我们在前面的章节中所讨论的,HFT 系统中服务器的目的是处理基准交易功能:接收市场数据、执行算法模型以及向交易所发送订单。该系统有一个网络接口,用于向企业发送数据和从企业接收数据,或与公司内部的其他交易系统进行通信。第 5 章,动态网络,重点关注这一方面。一旦数据包离开线路,中央处理器 (CPU) 就会执行最繁重的工作。数据包将从网络接口到达主机内存;然后,CPU 会将数据包的片段拉入缓存,以便 CPU 执行核心可以对数据包的内容进行解码和操作。
要实现低延迟,您需要考虑您的软件如何在 CPU 中执行,以及数据如何从各种硬件组件流出以供您的交易系统和算法处理。在以下部分中,我们将了解 CPU 的工作原理以及影响软件性能的一些 CPU 微架构细节。 CPU,从多处理器到多核
CPU 是一个或多个处理器内核的集合,它们获取并执行程序指令。这些指令可以作用于存储在内存中的数据或与连接设备的接口。这些设备通常称为输入/输出 (I/O) 设备,通过一些扩展总线连接到 CPU,例如 PCI Express (PCIe)。过去,你需要在一台计算机上有多个物理芯片来实现多处理。在过去的十年中,为了应对摩尔定律强加的缩放限制,大多数出货的 CPU 在单个硅芯片上都有多个内核。随着硅特征(例如晶体管)变得越来越小,制造过程中的良率(全功能芯片的数量)成为一个问题,因此在单个封装中出现了多芯片(有时称为小芯片)的趋势。
CPU核心非常擅长执行许多小的逻辑操作。例如,CPU 可以执行基本的算术运算(加、减、乘和除)和逻辑运算(AND、OR、NOT、XOR 和位移)。CRC32、高级加密标准 (AES) 算法的步骤和无进位乘法(例如 PCLMUQDQ)等更专业的运算也由某些 CPU 内核直接实现。CPU 还可以处理从内存加载或从输入设备读取的信息。CPU 还可以根据它在别处计算或读取的信息来改变它的执行路径。这些控制流指令是高级语言构造的构建块,例如条件语句或循环。
当市场数据到达网络接口时,CPU 会对其进行处理。这意味着解析通过网络发送的数据,跨交易系统的不同功能部分管理该市场数据,并可能将由该市场数据触发的订单发送到交易所。在第 2 章交易系统的关键组件中,我们描述了基本元素。我们讨论了网关、订单簿和交易策略都是协同工作以触发订单的组件。对于单个 CPU 执行核心,这些操作中的每一个都必须按顺序发生,这意味着一次只能处理一个数据包。这意味着数据包可以排队等待前一个数据包完成处理;这会增加消息在交易系统可以将此新数据提供给交易策略之前等待的时间。为了减少延迟,我们希望许多处理单元并行工作,尽快移交已处理的市场数据,以继续处理已到达的后续消息。在 20 世纪 90 年代,多路服务器开始流行,在同一块主板上配备两个或更多 CPU。由于摩尔定律的限制,单 CPU 内核无法扩展性能,因此 CPU 供应商开始在单个芯片上添加多个处理内核。现代服务器可以有多个 CPU 插槽,每个插槽都有多个 CPU 内核,从而在一台机器上实现相当大的并行度。
图 4.2 描绘了一个现代的多路系统架构。内存或 I/O 设备直接连接到特定的 CPU 插槽。这些被称为本地 CPU 。其他 CPU 可以使用互连连接到单个系统中,例如 Intel 的 Ultra Path Interconnect 或 AMD 的 Infinity Fabric。假设一个 CPU 试图访问内存或连接到另一个 CPU 的 I/O 设备。在这种情况下,这被称为访问远程资源。当我们将一个 CPU 访问其本地资源所需的时间与远程 CPU 通过互连访问其本地资源所花费的时间进行比较时,我们发现互连比仅访问本地内存要慢得多。我们称此访问时间为非统一,并将这些架构称为非统一内存访问 (NUMA)。术语 cache-coherent NUMA 或 ccNUMA 指的是即使另一个 CPU 内核修改了数据,CPU 内核也能保证具有正确的内存视图。NUMA 架构可以扩展到大量内核。可以将每个 CPU 视为一个单独的计算机系统,所有这些都通过结构相互连接。
图 4.2 – 四路 NUMA 架构。请注意 CPU 如何在此配置中形成完全连接的图形
图 4.2 还代表了更多的组件。PCIe 是连接其他设备的总线,例如网络接口卡 (NIC)。当 NUMA 架构中存在多个 CPU 时,其他 CPU 可以通过互连总线请求数据来共享数据。 关于超线程和同步多线程的说明
同时多线程,在 Intel CPU 上称为超线程,是 CPU 跟踪多个并行执行状态(在超线程的情况下是两个这样的状态)的技巧。当一个执行状态需要等待高延迟事件(例如从更高级别的缓存或 RAM 中获取数据)时,CPU 会切换到另一个执行状态,同时等待获取完成;这是一种自动线程,由 CPU 本身管理,使每个物理内核显示为多个虚拟内核。
使用超线程将物理内核的数量增加一倍是一种诱惑,但这会引入难以控制的延迟,就像上下文切换一样。
图 4.3 描述了在一个超线程内核中使用超线程。我们可以观察到,如果一个任务在同时运行另一个任务时需要等待访问内存段,那么硬件可以伪造并发执行。如果系统调用(或中断)要求访问内核(Kernel),则所有任务都将暂停。
图 4.3 – 超线程
超线程的主要问题是它取消了任务切换的控制(在软件级别),这会产生更高的抖动和更高的延迟。 主存储器或 RAM
主存储器通常称为随机存取存储器 (RAM),是用于程序指令和数据的大型非持久性存储器。RAM 是从 I/O 设备(如网卡或存储设备)读取任何数据的第一站。现代 RAM 可以以高吞吐量突然返回数据,但是当请求某个地址的数据并且数据可用时会以延迟为代价。
在典型的 NUMA 架构中,每个 CPU 都有一些本地 RAM。许多配置将等量的 RAM 连接到每个 NUMA 节点,但这不是硬性要求。访问 RAM 的延迟可能非常高,尤其是在远程 NUMA 节点上。因此,我们需要其他方法来隐藏这种延迟或缓冲数据,靠近执行某些代码的 CPU。这就是缓存发挥作用的地方。 缓存
具有许多内核的现代处理器具有每个内核的本地缓存和由单个插槽上的所有内核共享的缓存。这些缓存旨在利用程序通常在特定时间窗口内对同一内存区域中的数据进行操作这一事实。数据访问的这种空间和时间局部性为 CPU 提供了隐藏访问 RAM 的延迟的机会。
图 4.4 显示了现代多核 CPU 的典型缓存层次结构。 L1缓存分为两部分:数据缓存和指令缓存。L2 和 L3 缓存将自由混合指令和数据,主存储器也是如此。
图4.4——缓存系统
我们现在将讨论缓存系统的结构。 缓存结构
不是一次从主存储器读取单个字或字节,每个缓存条目通常存储特定数量的字,称为缓存行。这一整行被同时读取和缓存。读入缓存行时,需要逐出另一行以为新缓存行腾出空间。逐出哪条线路通常是根据LRU来确定的,但也存在其他方案。不同级别的缓存具有不同的缓存行大小——这是 CPU 设计本身的属性。有关如何将数据结构与缓存行大小对齐以增加缓存命中几率的各种细节,主要是在访问许多相关数据结构时。 L1 cache
L1 高速缓存(1 级)是计算机系统中最快的可用内存,它靠近 CPU 的执行单元。L1 缓存具有 CPU 最近访问并加载到寄存器中的数据。CPU 供应商决定 L1 缓存大小。
L1高速缓存被分为数据缓存和指令缓存。指令缓存存储有关 CPU 必须完成的操作的信息,而数据缓存存储将执行处理的数据。 L2 cache
L2 缓存(2 级)比 L1 缓存慢但更大。现代 L2 内存缓存以兆字节 (MB) 为单位,而 L1 缓存以千字节 (KB) 为单位。L2 存储的大小因 CPU 而异。但是,它通常介于 256KB 和 8 MB 之间。当前大多数 CPU 的 L2 缓存都大于 256 KB,这在现在被认为很小。当今最强大的 CPU 具有超过 8 MB 的 L2 内存缓存。L2 缓存在性能方面落后于 L1 缓存,但它仍然比系统 RAM 快得多。L1 缓存一般比 RAM 快 100 倍,而 L2 缓存大约快 25 倍。 L3 cache
L3 缓存最大,但也是最慢的。L3 缓存包含在现代 CPU 中。L3 缓存更类似于整个芯片可能使用的全局内存池,而 L1 和 L2 缓存专用于芯片上的每个内核。L3 缓存就是我们所说的受害者缓存:从内核本地的 L1 和 L2 缓存中逐出的任何缓存行都将在发送到主内存之前传送到 L3。它通常是完全关联的缓存,位于 CPU 缓存的重新填充路径中,用于存储从该级别缓存中逐出的所有块。所有内核共享现代 CPU 上的 L3 缓存。 共享内存
今天的大多数计算机系统,尤其是那些有多个插槽的系统,都会产生一种用一个主内存池单一设计的错觉。我们将这些称为共享内存系统,其中在任何 CPU 上运行的程序都可以访问连接到另一个 CPU 的任何内存,就好像它是运行代码的 CPU 的本地内存一样。
今天,有两种类型的共享内存模型:统一内存访问 (UMA) 和非统一内存访问 (NUMA)。UMA 使用单一内存控制器,所有 CPU 通过这个单一内存控制器与系统内存进行通信。在大多数情况下,内存控制器是所有 CPU 直接连接的独立芯片。在 NUMA 架构中,有内存控制器,内存物理连接到特定的插槽。NUMA 架构相对于 UMA 的主要优势是 NUMA 系统可以更快地扩展到更多数量的 CPUs,因为互连 NUMA 节点比将多个 CPU 连接到单个系统内存池要简单。
在 UMA 的情况下,随着更多微处理器的添加,共享总线变得拥塞并成为性能瓶颈。这严重限制了 UMA 系统扩展可用 CPU 数量的能力,并且增加了每个 CPU 核心必须等待主内存请求得到服务的时间。
当今市场上的所有现代多路服务器都是 NUMA 架构。每个 CPU 插槽都有其物理连接的内存池。由于每个 CPU 都存在多层缓存,因此 CPU 可能会缓存包含在另一个 CPU 内存中的旧版本数据(或者甚至另一个远程 CPU 将修改该 CPU 的本地内存)。为了解决这些情况,我们需要缓存一致性协议。这些协议使 CPU 能够确定它是否唯一拥有、共享或具有特定内存区域的本地修改版本,并在其他 CPU 尝试访问确切的内存位置时与它们共享信息。理想情况下,编写的应用程序很少需要使用这些协议,尤其是在延迟和吞吐量很重要的情况下,因为同步此所有权的成本很高。
SMP 和 NUMA 系统通常用于 HFT 系统,其中处理可以分布在在单个内存位置工作的多个处理器之间。在设计数据结构和系统以在交易系统组件之间传递消息时,必须考虑这一点。 I/O设备
有许多不同类型的 I/O 设备连接到计算机,例如硬盘驱动器、打印机、键盘、鼠标、网卡等等。在 HFT 中我们应该考虑的主要设备是第 5 章“运动中的网络”中描述的网卡。大多数I/O设备通过PCIe (Peripheral Component Interconnect Express)连接到CPU。PCIe 设备与 NUMA 基础设施中的特定 CPU 直接相关。在构建交易系统时,您需要考虑您的网络代码(例如市场数据网关)将哪个 CPU 保持在网络设备连接的 CPU 本地,以最大限度地减少延迟。
我们总是试图限制使用的设备是硬盘。访问硬盘上的数据成本非常高,因此很少在 HFT 系统中使用。然而,当我们回测交易策略时,信息存储在磁盘上。我们需要以特定方式存储数据以确保快速访问。我们不会在本书中讨论这部分,因为它不是特定于 HFT 系统的。
针对高频交易如何使用操作系统
对于 HFT 系统,主要的关键功能是进程调度。我们将在后面的章节中详细描述调度任务的过程。 用户空间和内核空间
操作系统的核心是它的内核。内核是位于应用程序和硬件之间的具有高度特权的代码块。内核通常提供许多服务,从管理网络和通信的协议栈到以设备驱动程序的形式在硬件设备之上提供抽象。内核具有很高的特权,可以控制系统的工作方式,包括从任意物理内存地址读取和写入、创建和销毁进程,甚至可以在系统上运行的应用程序使用数据之前更改数据。内核必须小心保护,只有受信任的代码才能在内核上下文中运行,称为内核空间。
用户空间是应用程序运行的地方。用户空间进程是具有多个线程的独立虚拟内存空间。用户空间进程的特权往往要低得多,需要内核的特殊支持才能访问设备、分配物理内存或更改机器状态。交易系统在用户空间中运行,但构建低延迟交易系统的挑战之一是尽量减少硬件和交易系统之间的抽象数量。毕竟,在不同格式之间转换数据、将上下文切换到内核或其他进程以传递消息或处理不必要的硬件状态更改所需执行的代码越多,运行关键交易系统代码所浪费的时间就越多。
一个重要的概念是地址空间的分离。正如我们将看到的,这部分与操作系统如何分配内存和 CPU 理解内存有关,但这也是一项安全性和稳定性功能。未经明确许可,一个进程不应影响内核或另一进程。如果没有共享内存或类似的通信技术,用户空间中的进程几乎无法直接相互交互。这同样适用于内核,因为进程可以直接与内核交互的方式很少。内核旨在保护对其敏感资源和数据结构的访问。 进程调度和CPU资源管理
任何软件都首先被编译并位于持久的长期存储(一些固态驱动器或硬盘)上。当我们想要启动交易系统(或任何软件)时,我们调用存储在磁盘上的一个或多个可执行文件。这导致操作系统创建一个或多个进程。
OS会将软件加载到主存中,创建一个虚拟内存空间,并调用一个线程来执行刚刚加载的代码。运行的软件、虚拟内存空间和一个或多个线程的这种组合称为进程。一旦加载,操作系统最终将调度进程的主线程。调度程序负责确定与进程关联的线程将在何处以及何时执行。调度程序可以跨多个执行核心管理线程的执行,这些线程可以跨多个物理 CPU 插槽并行调度。调度器是在众多 CPU 内核之上的抽象,就像在上一节中描述的现代计算机系统中一样。
当我们的进程多于可用的执行核心时,调度程序可以限制线程在介入与另一个等待线程交换之前执行多长时间。这称为多任务处理。将正在运行的进程从一个更改为另一个的动作称为上下文切换。
上下文切换是一个高昂的操作。OS保存被切换进程的执行环境,恢复被重启进程的环境。如前所述,交易系统利用多个内核来实现实时并行。可用的物理执行核心越多,并行运行的线程就越多,通常将一个线程映射到一个执行核心。
现代操作系统中使用两种传统的进程调度方法:
抢占式多任务:Linux 和大多数操作系统都采用抢占式多任务处理方法。抢占式多任务旨在保证一个进程不能独占系统。每个进程都有特定的运行时间。这段时间称为时间片。调度程序将在该时间片到期后停止进程运行。除了防止进程消耗太多时间之外,这种方法还允许调度程序做出全局处理决策。许多抢占式多任务调度程序试图了解 NUMA 拓扑并在其资源附近执行线程,但这通常很难实现。
协作式多任务处理:这主要是因为它将允许进程运行到进程自愿决定停止运行为止。我们将进程自愿选择停止运行的行为称为屈服(yielding)。这种方法对于实时操作系统是典型的,因为工程师不希望延迟敏感代码被调度程序或其他正在运行的任务中断。您可以想象,这在用于某些关键安全过程的实时控制系统中将是灾难性的,或者如果您延迟订单到达市场,直到其他人获得该流动性很久之后。诸如 Linux 之类的操作系统具有一种可用的协作式多任务处理形式,如果谨慎使用,它对于对延迟敏感的代码很有用。通常,这是为了支持使用 Linux 的实时应用程序。
几乎所有的任务调度器实现都提供了多种机制来调整调度器的行为。这可以包括基于每个进程的指导,例如优先级、NUMA 和执行单元关联、内存使用提示、I/O 优先级规则等。Linux 允许将多个调度规则应用于正在运行的进程,从而使某些任务组可以使用实时调度规则。其中许多设置在设计低延迟系统时很有用,但需要谨慎使用;不正确的优先级排序可能会导致优先级倒置或其他死锁情况。
调度程序将始终对其默认配置中的所有资源和进程保持相同的公平性。这提供了在预定限制时间内从一组请求中授予每个请求的保证,即使调度请求原语是不公平的或随机的。在第 6 章 HFT 优化——体系结构和操作系统中,我们将解释如何通过限制上下文切换的次数来使此进程调度专门用于 HFT 系统。 内存管理
软件需要在内存中提供其指令和数据才能执行。操作系统指示 CPU 哪个内存属于哪个进程。
操作系统必须跟踪分配了哪些内存区域,将内存映射到每个进程,并指定分配给给定进程的内存量。内存管理单元访问的地址空间称为物理地址空间。这是您计算机上可用的物理内存。CPU 会将此空间的一部分分配给正在执行的进程。这些细分的空间被称为虚拟地址空间。内存管理单元的工作是实时将该空间从物理空间映射到逻辑空间,以便 CPU 可以快速找出虚拟地址对应的物理地址。 分页内存和页表
现代操作系统不知道进程正在访问或存储的对象或数据。相反,操作系统专注于基本的系统级内存单元。操作系统管理的最基本的内存组是一个页面。页面是物理内存中大小均匀且精确对齐的区域,其大小通常由 CPU 在体系结构上确定。可以使用 CPU 中内置的称为内存管理单元 (MMU) 的硬件将页面映射到特定的虚拟地址。通过将不同的物理页面重新映射到连续的虚拟范围,应用程序开发人员不必考虑硬件如何管理内存或页面在物理内存中的位置。操作系统执行的每个进程都有其页面映射,称为页表。
图 4.5 表示使用页面的进程。任何物理页面都可以存在于多组页面映射中。这意味着可能运行在不同 CPU 内核上的各种线程可以访问其地址空间内的同一内存页。
图 4.5 – 页面和进程
物理地址和虚拟地址的来回转换由 CPU 中的硬件自动完成。因此,如果我们正在翻译的信息位于靠近 CPU 的快速位置,翻译的性能将会提高。实际上,用于存储此信息的位置页表通常位于 CPU 中的专用寄存器中,但这只有在页表很小的情况下才有可能。CPU 中一个称为转换后备缓冲区 (TLB) 的专用高速缓存用于任何实际的页表。由于页表是内存中的数据结构,如果进程的地址空间太大而无法放入 TLB,大多数 CPU 都有硬件将相关页表从其他 CPU 的缓存甚至主内存中拉入 TLB 。
分页会损害进程的性能。当 TLB 中存在缓存未命中时,操作系统必须从内存中的其他位置加载数据。在 HFT 系统中,我们有时会通过增加页面大小来最小化 TLB 缓存未命中的影响。大于 4 KB 标准基页大小的虚拟内存页面称为大页面。对于大数据集上的频繁访问模式,大页面可以提高内存速度。大页面是有代价的——跟踪大页面的 TLB 有时比管理标准页面的 TLB 小几个数量级,这意味着如果映射了许多大页面,则可能需要更频繁地访问内存。因此,必须谨慎使用大页面。 系统调用
系统调用意味着用户空间应用程序向操作系统内核请求服务。系统调用是应用程序与操作系统通信的一种方式。系统调用是软件向操作系统内核发出的执行某些敏感操作(例如操纵硬件状态)的请求。请求现代操作系统上的一些关键系统调用来处理进程创建和终止、管理磁盘上的文件、管理 I/O 设备以及与外界通信。
当请求系统调用时,如果请求被允许,内核将执行该操作。对于许多系统调用,如果调用成功完成,应用程序会收到来自内核的一些响应。系统调用完成后,如果时间片中还有时间,或者没有更高优先级的任务等待 CPU 时间,调度程序可以安排请求任务恢复。内核将结果提供给应用程序,然后在该过程完成后将数据从内核空间传输到内存中的用户空间。
一些特定的系统调用,例如获取系统日期和时间,可能需要几纳秒才能完成。更扩展的系统调用,例如连接到网络设备或与磁盘上的文件交互,可能需要几秒钟。大多数操作系统为每个系统调用启动一个单独的内核线程,以最大限度地减少瓶颈。多线程操作系统可以同时处理多个系统调用。HFT 系统将大量使用这种并发执行的概念,例如使用线程。
现代版本的 Linux 提供虚拟动态共享对象 (vDSO),将一些特殊的内核空间函数导出到用户空间,尤其是那些与检索当前系统时间相关的函数。vDSO 的强大之处在于,这些函数在内核的控制下,因此了解硬件细节,直接在用户空间进程中执行。不像 open 和 read 系统调用需要进入内核的整个过程(因此需要完整的上下文切换),诸如 clock_gettime 的函数(至少在 CLOCK_MONOTONIC 的情况下)具有非常低的调用开销,因为调用是在 vDSO 中。 线程
任何进程中最基本的分工是线程。通过跨多个线程进行工作,可以实现并行性。单个进程内的所有线程共享一个公共虚拟内存空间。每个进程,一个或多个线程的分组,都有自己独特的内存空间。交易系统的主要活动是在不同功能(可能是进程)之间共享数据,以决定发送订单。在优化并发功能之间的通信时,将考虑线程或进程的使用。这也会影响您构建在线程和进程之间传递数据的方式。线程之间传递的数据可以利用内存分配中的并发性,允许您通过简单地向另一个线程提供指向数据结构中的消息的指针来传递数据。在进程之间传递数据要么需要一个由两个进程映射的共享内存池,要么将消息序列化到某个队列中,如第 6 章 HFT 优化 - 体系结构和操作系统中所述。
除了能够共享内存之外,线程的响应时间比进程快。如果一个进程被分成许多线程,一个线程的输出可能会在它完成执行时立即返回。它们的上下文切换时间也比进程短。
因为任何 HFT 系统都需要系统调用,所以必须抵消成本。我们将在第 6 章 HFT 优化 - 体系结构和操作系统中了解如何从线程和进程中获益。 中断管理
中断请求是外围设备在发生某些事情时提醒 CPU 的方式。然后 CPU 将停止其中一个处理核心并将上下文切换到分配给该设备的中断处理程序。限制可以创建上下文切换的中断次数;我们还将在第 6 章 HFT 优化——体系结构和操作系统中回顾这一点。
图 4.6 描述了在单核模型中使用中断(或系统调用)对 CPU 执行任务的时间的影响。我们可以观察到调度器会在当前运行的任务和内核中的中断上下文之间切换。内核花费更多的时间来处理中断请求,然后可用于运行用户任务的 CPU 时间就更少了。
图 4.6 —— 中断或系统调用对任务调度的影响
图 4.7 显示了两个 CPU 内核的好处,有两个不需要共享时间的任务。这个例子表明,如果我们将任务固定到给定的核心,我们将减少上下文切换的次数并减少内核中断的影响。此示例还假设中断请求仅由一个内核提供服务。因此,只有任务 1 会中断以服务硬件。
物理层:这是两台机器用来通信的媒体,包括光纤、铜缆和卫星。所有这些媒体都有不同的特性(延迟、带宽和衰减)。根据我们想要构建的应用程序类型,我们将利用一个与另一个。该物理层被认为是 OSI 模型的最低层。它涉及通过网络以电或光方式从发送方的物理层向接收方的物理层传送原始非结构化数据位。网络集线器、电缆、中继器、网络适配器和调制解调器是在物理层找到的物理资源的示例。
这种类型的交换机需要 MAC 地址才能将帧转发给正确的接收者。所有接收到的 MAC 地址都将保存在一个转发表中。该表允许交换机以非常有效的方式转发数据。与可以基于 IP 地址传输数据包的更高级别的交换机(高于 3)不同,第 2 层交换机不能使用 IP 地址并且没有优先级机制。 第3层交换
第 3 层交换机是一种设备,其作用如下:
基于源地址和目标地址分析和路由数据包的具有智能 IP 路由的路由器
同一子网上的交换机链接设备
我们现在将讨论能够使用公共地址从许多私有 IP 地址路由数据的系统。 网络地址转换
将私有 IP 地址转换为公共地址的过程称为网络地址转换 (NAT)。大多数路由器使用 NAT 来允许许多设备共享一个 IP 地址。当机器与交换机通信时,它会寻找到交换机的方向。此请求作为数据包从机器发送到路由器,然后转发给企业。路由器必须首先将源 IP 地址从私有本地地址转换为公共地址。如果数据包包含私有地址,接收服务器将不知道将信息发送回何处。由于 NAT,信息将使用路由器的公共地址而不是笔记本电脑的私有地址返回到笔记本电脑。
对于使用它的任何设备,NAT 都是一项资源密集型操作。这是因为 NAT 需要读写每个 IP 数据包的头和负载信息来完成地址转换,这是一个耗时的过程。它会增加中央处理器 (CPU) 和内存的消耗,这可能会降低吞吐量并增加数据包延迟。因此,在实际网络中安装 NAT 时,了解 NAT 对网络设备(特别是路由器)的性能影响变得至关重要,尤其是对于 HFT。大多数现代交换机至少可以在 ASIC 中执行静态 NAT,但越来越多的交换机也可以执行动态 NAT,但性能会有所下降。
我们详细研究了如何传输数据包。我们现在将描述设置数据包转发规则的协议。
重要的协议概念
因为 FIX 协议是基于字符串的,所以解析器可能需要一些时间来处理流。 FAST 协议的开发速度比 FIX 协议更快。 FAST协议
FAST 协议是 FIX 协议的高速版本。市场数据通过在 UDP 之上运行的 FAST 协议从交易所或馈送处理程序传输到市场参与者。FAST 消息具有用于传输元数据和有效负载数据的各种字段和运算符。 FAST 被设计为使用尽可能少的带宽。因此,它使用了多种压缩技术,如下所述:
在图5.20中,RX缓冲区是一个循环缓冲区(或ring buffer),它是一种使用固定大小缓冲区的数据结构,端到端相连(主要是为了避免使用锁)。 DMU 允许 I/O 设备绕过 CPU 直接向主内存传输数据或从主内存接收数据,从而加快内存操作。
然后 NIC 触发一个中断,让 CPU 处理这个数据包。中断处理程序通常分为两半——上半部分和下半部分。上半部分处理任何需要紧急完成的工作,下半部分处理所有其他处理。上半部分将管理诸如确认中断和将数据从网络移动到缓冲区以供下半部分进行后续处理等活动。处理器会从用户空间切换到内核空间,查找中断描述符表(IDT),调用相应的中断服务程序(ISR)。然后,它将切换回用户空间。这些操作是在 NIC 驱动程序级别完成的。
网络对于高频交易至关重要。从关键路径中节省微秒以在网络中发送订单是关键。在网络搭建和系统运行的过程中,对网络流量进行分析是必不可少的。在高频交易中,安全性不是真正的问题,因为网络大部分时间都位于同一地点。我们将给予更多权重的监控部分是分析数据丢失、延迟和中断的数量。我们需要确保网络正常运行并提供最佳性能。 数据包捕获和分析
捕获以太网帧以供检查或分析称为数据包捕获。这个词也可以指数据包捕获程序生成的文件,通常以 .pcap 格式保存。抓包是一种典型的网络故障排除工具,也用于查找网络流量中的安全漏洞。数据包捕获提供了重要的取证信息,可以在出现订单数量被拒绝的问题后加强调查,这看起来像是网络延迟问题。 什么是数据包捕获,它是如何工作的?
可以通过多种方式捕获数据包。可以通过网络设备(例如路由器或交换机)执行数据包捕获,这些设备具有称为测试接入点 (TAP) 的特定硬件(我们将在下一节中介绍)。最终目标决定了使用的方法。无论使用何种机制,数据包捕获都是通过创建通过网络中给定位置的部分或所有数据包的副本来工作的。
最简单的入门方法是从您的系统中捕获数据包,但有一些限制。默认情况下,网络接口仅处理发往它们的流量。您可以将接口置于混杂模式或监控模式,以获得更全面的网络活动视图。请记住,此方法仅捕获网络的一部分。例如,在有线网络上,您只会观察到计算机所连接的本地交换机端口上的活动。
端口镜像、端口监控和交换端口分析器 (SPAN) 是路由器和交换机上的功能,允许我们复制网络流量并将其传输到特定端口。许多网络设备都具有数据包捕获功能,可用于直接从硬件的命令行界面 (CLI) 或用户界面 (UI) 诊断问题。
专用网络 TAP 非常适合在特别大或繁忙的网络上进行数据包捕获。 TAP 是一种收集数据包的昂贵方式,但不会影响性能,因为它们是专用硬件。为了使 TAP 有效,有必要捕获两个方向(传输 (TX) 和 RX)。我们需要同时挖掘 RX 和 TX 端来构建完整的画面。 以太网 TAP——无源与有源 TAP 的权衡
网络 TAP 是再现流量以进行监控和分析的最精确技术。有多种网络分路器,每种分路器在网络正常运行时间和分析可靠性方面都有自己的优势。此方法可以是无源和有源网络分路器。无源和有源 TAP 之间的区别可能令人困惑。 无源网络TAP
其网络端口之间没有物理分隔的设备称为无源网络 TAP,如下图所示。这意味着流量可以继续跨网络端口流动,即使设备断电也能保持连接:
图 5.21 —— 无源网络TAP
这适用于具有 10/100 米 (10/100M) 铜接口和光纤 TAP 的网络 TAP。光纤 TAP 的工作原理是将入射光分成两条或更多条路径,并且不需要电力。尽管10M 或 100M 铜线 TAP由于网络端口之间缺乏物理隔离导致它们完全是无源的,但在使用时依然需要电力。在这样的情况下,链路在断电期间保持运行,没有故障转移时间或链路恢复延迟。 有源网络TAP
由于 TAP 内部使用的电气组件,有源 TAP 在网络端口之间具有物理隔离,这与无源 TAP 不同。因此,他们需要一种故障安全机制,以确保即使 TAP 断电,网络也能保持运行。该系统通过在小工具打开时保持一组继电器打开来工作。当断电时,这些中继切换到通过 TAP 的直接流量,确保网络运行。您可以在下图中看到对此的说明:
图 5.22 —— 无源网络TAP
这两个 TAP 将有助于捕获市场数据以分析延迟并解决网络中的问题。如果此数据的时间不准确,则仅获取此数据是不够的。在 HFT 中准确测量时间是必不可少的。在下一节中,我们将解释如何操作。
重视时间分配