亚马逊AWS官方博客

高频交易底层优化方案

随着区块链行情热度增加与玩家增多,也为 Cefi 系统构建带来了新的机遇与挑战:相对 Defi 的套利机制多样化,Cefi 的盈利机制较为单一,因此需要我们对交易中心架构更加了解,也需要我们更好地利用云带来的优质底层架构来保证收益稳定。本文会提供在亚马逊云科技上构建 Cefi 高频交易系统的一些优化思路与硬件选择参考,也欢迎各位联系我们一起讨论更好的方案。

前提:交易中心会在其系统前面使用 CDN 技术来提高业务在全球范围内的稳定性,针对高频交易的场景,如果交易中心提供了 VIP link 或者 Colo 的模式,应尽量获取到该资源以获得最大部分的延迟降低。

亚马逊云科技上的 Region 与 AZ

第一步我们需要做的就是了解亚马逊云科技 Infra 和交易中心的架构,亚马逊云科技 Region 架构如下图所示:

可以看到,亚马逊云科技的 Region 设施十分庞大,已经默认帮我们做好了同城灾备。再来看一下常见的交易中心架构:

一个完整的交易中心一般会有 Web 业务系统、交易撮合系统、运营后台系统、资金管理系统等子系统,在构建这些系统时,为了保证尽可能快速完成交易,交易中心往往会摒弃常见的同城多数据中心的高可用架构,而采用主从系统的方式来对外提供服务,体现在亚马逊云科技的硬件设施上,主要是会采用单可用区(简称 AZ)的形式部署某一套业务系统,典型场景比如现货被单独部署在亚马逊云科技某区域中的某一可用区域,币本位则被单独部署在其他可用区(可能随着交易中心架构变化而变化,但是为了保证撮合效率一般都是单 AZ 部署)。 在亚马逊云科技中可用区之间的延迟一般会在 1-3ms 左右,所以首要是选择正确的,也就是与交易业务系统所在相同位置的可用区(前提是已经获取了 Colo 或者 VIP link)。

vCPU 和 Core

许多 Amazon EC2 实例类型的 CPU 都是 Intel CPU,支持超线程技术。CPU 超线程就是利用特殊字符的硬件指令,把两个逻辑内核模拟成物理芯片,让单个处理器能使用线程级并行计算,从而兼容多线程操作系统和软件,使运行效率提高。在 EC2 中的具体表现为,每个线程都表示为实例上的一个虚拟 CPU(vCPU),默认启动的大部分 EC2 信息页面中,vCPU 表示的都是线程核(虚拟 CPU/vCPU)。

在高频交易中,对于一些时间敏感的、决定性的进程,为了减少进程的 CPU 切换,保证策略计算时的缓存命中率和计算效率,往往需要对相关进程进行绑核操作,常见命令比如 taskset 。但是在启用了超线程的 CPU 架构中 CPU0/CPU1 实际上是同一个物理核,L1、L2 缓存在 CPU 的设计中为物理核心单独持有,L3 为共享,图示如下(超线程中,Core0 的 T0 & T1 会是 vCPU 的 CPU0, CPU1):

因此,即使绑定 vCPU 也存在可能的资源竞争,因此,高频交易的场景中,如果使用的 EC2 是 Intel 的 CPU,建议关闭超线程。关闭超线程如下图所示(创建实例时,展开最后的高级选项可以找到):

如图所示需要注意两个参数:

Core count:当前EC2的物理核心数量;
Threads per core:每个核心的线程数(Intel CPU默认为2);

将 Threads per core 改为 1,Core count = Number of vCPUs 即关闭超线程。

EC2 型号选型

亚马逊云的 EC2 分为多种类型,以下是对现有型号的简单归纳:

高频交易的场景中,我们的业务核心性能需求主要为两点,CPU 的计算能力与网络性能。

如上图所示,可根据需求组合出适合高频交易业务的机型:

  • C7i(采用第四代 intel 至强 CPU 的计算型 EC2 )
  • C6in(采用第三代 intel 至强 CPU 的计算型 EC2,附带网络增强)
  • C7gn(采用第三代 graviton CPU 的计算型 EC2,附带网络增强)

这三款机型的选择优先级可综合考虑适配性、计算性能和网络带宽三个方面。

从适配性和计算性能上来说,最建议的 CPU 是第四代 Intel 至强 CPU,也就是 C7i ,但是 C7i 的型号截止到目前为止(2024.3.20)还未发布网络增强机型;从适配性和网络增强的需求上考虑,可以优先第三代 Intel 至强 CPU 的计算型 EC2,也就是 C6in;C7i 和 C6gn 两者之间除了 CPU 差异外,C7i 机型的内存是 DDR5,而 C6in 是 DDR4,DDR5 相对于 DDR4 内存带宽提高 50%;如果计算性能和网络增强的需求都不可取舍,则建议采用 C7gn 机型 ,但需注意 C7gn 采用的 CPU 是亚马逊云科技自研的 Graviton3 ,一款基于 ARM 架构的 CPU,C7gn 具体参数如下:

  • 2.6 GHz clock speed (Graviton2: 2.5GHz)
  • 300 GB/sec max memory bandwidth
  • DDR5 RAM 4800 channels (Graviton 2: DDR4-3200 channels)
  • 核数 64 cores
  • 内核架构:Neoverse v1 cores (Graviton 2: Neoverse N1 cores)
  • 256-bit SVE (Scalable Vector Extension)

作为一款服务器版本的 ARM CPU,在高频场景中,Graviton3 的优势主要体现在:

  • 指令并行,从 graviton2 的 5 个指令并行增加到 8 个指令并行;
  • 内存带宽 300GB/s;
  • 价格上同规格一般只有 intel 的 80%;
  • 无超线程,1 vCPU = 1 物理核;
  • RISC 指令集,编译优化更简单;

综上,我们建议在云上进行高频时首选以上三款机型测试,并根据具体业务的需求侧重点再进行优先级排序。

EC2 Size 选择

除了 EC2 的型号以外,还有一个值得注意的点是 EC2 的 size,以上文中 c6in,c7i,c7gn 几款机型为例,从 8xlarge 开始,网络带宽就变成固定的带宽,而在更小的机型中,往往会有 up to 这个限定词,意味着带宽非固定。在高频交易场景中,建议使用 8xlarge 以上的机型来保证固定高带宽,保障业务稳定。

得益于亚马逊云科技 Nitro 技术,我们不用在裸金属和大机型的性能中过多纠结。以下是关于 C5n 机器中,裸金属和同规格虚拟机的性能测试,可以看到性能差小于千分之一:

除此以外,采用更大的机型和我们的业务逻辑以及单核性价比也有关系。大部分的高频交易分成两个模块,获取行情和策略下单,同前文所讲,为了保证低延迟,我们一般会对进程进行绑核处理,比如行情进程绑定 CPU1,策略下单绑定 CPU2,同样,为了提高收益率,我们一般不会只进行单一币对或单一策略的交易,一般是多行情多策略,也就是行情进程 + n*策略下单进程,此时大机型可以提高行情的利用率,减少重复行情获取,提升单核资源的性价比。

EC2 的多 IP

在高频场景中,我们往往不会局限在单个账号进行交易,而是通过多账号进行交易,这时容易触发交易中心设置的单个 IP Limit。Amazon EC2 支持多网卡多 IP ,以推荐的 c7gn 机型为例,官网数据如下:

单机可以容纳的 IP 上限为最大网络接口数*每个接口的私有 IPv4 地址数(每个私有 IPv4 可对应绑定一个公有 IPv4),因此,大的机型可以帮我们在单机交易上获得更多的便利。

CPU c-state / p-state

C-state 控制核心在处于空闲状态时,可以进入的睡眠级别。C-state 从 C0(最浅空闲状态,此时核心完全唤醒并在执行指令)开始编号,一直增进到 C6(最深空闲状态,此时核心关闭)。

在我们上述推荐的机型中,c7i.metal-24xl & c7i.metal-48xl 支持进行 c-state 和 p-state 控制;而 c7i.large | c7i.xlarge | c7i.2xlarge | c7i.4xlarge | c7i.8xlarge | c7i.12xlarge | c7i.16xlarge | c7i.24xlarge | c7i.48xlarge 机型仅支持 c-state 控制。

亚马逊云科技 Graviton 处理器具有内置的节能模式,并以固定频率运行。因此,它们不提供操作系统控制 c-state 和 p-state 的能力。

在高频量化场景中,尽量减少 CPU 进入睡眠状态和减少使用低频以更高的能源消耗获取一定程度的延迟优化。

在 Amzon linux2 中,可以使用以下方式限制 CPU 睡眠:

1. 使用所选编辑器打开 /etc/default/grub 文件。

[ec2-user ~]$ sudo vim /etc/default/grub

2. 编辑 GRUB_CMDLINE_LINUX_DEFAULT 行并添加 intel_idle.max_cstate=1processor.max_cstate=1 选项,以将 C1 设置为空闲内核的最深层 C 状态。

GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,115200n8 net.ifnames=0 biosdevname=0 nvme_core.io_timeout=4294967295 intel_idle.max_cstate=1 processor.max_cstate=1"
GRUB_TIMEOUT=0

3. intel_idle.max_cstate=1 选项为使用 Intel 处理器的 EC2 配置 C-state 控制,processor.max_cstate=1 选项用于为基于 AMD 处理器的实例配置 C 状态限制。

4. 保存文件并退出您的编辑器。

5. 运行以下命令重新构建启动配置。

[ec2-user ~]$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg

6. 重启实例以启用新的内核选项。

[ec2-user ~]$ sudo reboot

Kernel-bypass

Linux 操作系统中,一个数据包的收发过程如下:

  1. 当⽹卡收到报文后,通过 DMA 机制将报文放到内存。
  2. ⽹卡触发中断通知系统有报文到达(⼀个报文,⼀个中断),系统分配 sk_buff,将报文 copy 到这块 sk_buff 中,然后交由协议栈处理。
  3. 经过协议栈处理,将报文上送用户态应用程序处理。

这个过程在一些需求低延迟的场景中存在比较多的资源消耗:

  • ⼀个报文⼀个中断,中断将打断 CPU 并且涉及上下文切换,将消耗系统资源;
  • 每个报文都要分配 sk_buff,申请分配将消耗很多资源,同时 Linux 为了兼容很多协议将 sk_buff 设计的过于复杂和庞大,导致处理变得缓慢;
  • 当用户的程序需要收发包时涉及多次系统调⽤和上下文切换,这些切换将消耗⼤量的系统资源。

为了解决内核协议栈带来的瓶颈问题,可以使用 kernal bypass 的方式来绕过内核对数据包的处理,采用诸如零拷贝,轮询等方式减少 CPU 中断带来的性能问题,一般的 kernal bypass 技术依赖特殊的网卡,比如 SolarFlare 的网卡等,但是云上我们没有此类条件,因此可以考虑采用 DPDK(Data Plane Development Kit)。

运行在用户空间中的 DPDK 应用程序利用自身提供的数据平面库来收发数据包,绕过 Linux 内核协议栈对数据包处理过程。

在 Linux 协议栈处理数据包的的流程: 网卡 -> 驱动 -> 协议栈 -> Socket 接口 -> 业务

DPDK 处理数据包的的流程:网卡 -> DPDK 轮询模式-> DPDK 基础库 -> 业务

DPDK 采用轮询的方式替代 CPU 中断,这会大量减少 CPU 中断带来的性能影响,此外,DPDK 也提供其他特性提高性能:

  • 用户态驱动:规避不必要的内存拷贝和系统调用,便于快速迭代优化。
  • 亲和性与独占:特定任务可以被指定只在某个核上工作,避免线程在不同核间频繁切换,保证更多的 cache 命中。
  • 降低访存开销:利用内存大页 HUGEPAGE 降低 TLB miss,利用内存多通道交错访问提高内存访问有效带宽。

值得注意的是,DPDK 需要独占一个 CPU 核心,与前文提到的建议任务绑定核心相匹配,也是推荐使用更大机型的原因之一。

然而 DPDK 的配置与代码开发是一项比较复杂的工作,而能带来的优化效果为 us(微秒)级别,相对有限,因此优先级可以降低。

EC2 的网络自检 +  ENA 启用

高频交易对网络要求较高,而 CloudWatch 的指标默认基于五分钟(最细粒度基于每分钟)计算平均值而无法及时发现网络瓶颈,容易导致业务受损时间较长(比如 CPU 与内存正常,但 pps 达到限制,导致请求 Timeout)。

结合最近 Web3 市场火热的现状,高频交易场景中可能会遇到偶发的进出流量(收取大量行情数据或者多进程发送大量交易请求)的大幅增长,为及时检测到网络性能瓶颈不影响业务运行,可安装 ENA 获得额外的网络性能指标监控,通过在 CloudWatch 中查看以下指标判断是否存在流量包等待或者丢弃的现象。

  • bw_in_allowance_exceeded: The number of packets queued or dropped because the inbound aggregate bandwidth exceeded the maximum for the instance.
  • bw_out_allowance_exceeded: The number of packets queued or dropped because the outbound aggregate bandwidth exceeded the maximum for the instance.
  • pps_allowance_exceeded: The number of packets queued or dropped because the bidirectional Packets Per Second (PPS) exceeded the maximum for the instance.
  • conntrack_allowance_exceeded: The number of packets queued or dropped because the network traffic for the instance exceeded the maximum number of connections that can be tracked.

上文中推荐的机型如运行在 Amazon Linux 上,则 ENA 都已默认启用,无需额外操作,如需验证可使用以下命令:

[ec2-user ~]$ modinfo ena
filename:       /lib/modules/4.14.33-59.37.amzn2.x86_64/kernel/drivers/amazon/net/ena/ena.ko
version:        1.5.0g
license:        GPL
description:    Elastic Network Adapter (ENA)

pps 达到上限而 CloudWatch CPU/MEM 使用率不高的监控情况示例:

总结

本文中,我们介绍了一些在亚马逊云科技上进行高频交易的硬件选择与优化建议,希望对您在亚马逊云科技上构建高频交易系统有一些帮助。除此之外还有很多方向值得我们进行尝试,比如 Linux 内核的参数优化,历史行情回测与行情时序存储,跨交易中心的优化线路等,也欢迎您联系我们一起讨论更好的方案。

参考链接

https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/MultipleIP.html#working-with-multiple-ipv4

https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/processor_state_control.html#c-states

https://docs.aws.amazon.com/zh_cn/whitepapers/latest/ec2-networking-for-telecom/overview-of-performance-optimization-options.html

https://aws.amazon.com/blogs/networking-and-content-delivery/amazon-ec2-instance-level-network-performance-metrics-uncover-new-insights/

https://aws.amazon.com/cn/blogs/china/how-to-use-dpdk-in-aws-ec2-instances-and-aws-based-container-platforms-i/

本篇作者

郑辉

亚马逊云科技解决方案架构师,负责基于亚马逊云计算方案架构的咨询和设计,在国内推广亚马逊云平台技术和各种解决方案。业余时间,他喜欢为自己和家人做美食。

郝志煜

亚马逊云科技解决方案架构师,他与客户合作构建各类创新解决方案,帮助客户解决业务问题并快速使用亚马逊云科技的服务。在工作之余,他还热爱各种极限运动,如滑翔伞、极限飞盘和自由潜。

杜晨曦

亚马逊云科技解决方案架构师,负责基于亚马逊云科技云计算方案架构的咨询和设计,在国内推广亚马逊云科技云平台技术和各种解决方案。