Boost ASIO 可以用来构建低延迟的应用程序吗?
Posted
技术标签:
【中文标题】Boost ASIO 可以用来构建低延迟的应用程序吗?【英文标题】:Can Boost ASIO be used to build low-latency applications? 【发布时间】:2017-11-10 20:00:26 【问题描述】:Boost ASIO 能否用于构建低延迟应用程序,例如 HFT(高频交易)?
所以Boost.ASIO使用了特定平台的最优解复用机制:IOCP、epoll、kqueue、poll_set、/dev/poll
还可以将以太网适配器与 TOE(TCP/IP 卸载引擎)和 OpenOnload(内核绕过 BSD 套接字)一起使用。
但是使用Boost.ASIO + TOE + OpenOnload可以构建低延迟应用吗?
【问题讨论】:
【参考方案1】:这是来自 Asio 作者的建议,已发布到公开的 SG-14 Google 群组(不幸的是,该群组存在问题,他们已移至另一个邮件列表系统):
我确实致力于超低延迟金融市场系统。像许多人一样 在业内,我无法透露项目细节。但是,我 将尝试回答您的问题。
一般:
您会发现基于硬件的解决方案具有最低延迟。
然后:供应商特定的内核绕过 API。例如,您对帧进行编码和解码,或使用(部分)TCP/IP 堆栈 不遵循 BSD 套接字 API 模型的实现。
然后:供应商提供的插入式(即 LD_PRELOAD)内核绕过库,它以如下方式重新实现 BSD 套接字 API 对应用程序透明。
Asio 与嵌入式内核旁路库配合得非常好。使用 这些,基于 Asio 的应用程序可以实现标准的财务 市场协议,处理多个并发连接,并期望 中值 1/2 往返延迟约 2 微秒,低抖动和高 消息率。
我对那些使用 Asio 进行低延迟工作的人的建议可以总结为 如:“旋转、固定和插入”。
Spin:不要睡觉。不要上下文切换。使用 io_service::poll() 而不是 io_service::run()。首选单线程调度。 禁用锁定和线程支持。禁用电源管理。禁用 C 状态。禁用中断合并。
Pin:分配 CPU 亲和性。分配中断亲和性。将内存分配给 NUMA 节点。考虑 NIC 的物理位置。将核心与 一般操作系统使用。使用具有单个物理 CPU 的系统。
Drop-in:根据性能和可用性选择 NIC 供应商 嵌入式内核绕过库。使用内核绕过库。
这个建议与具体的协议实现是解耦的 正在使用。因此,作为 Beast 用户,您可以应用这些技术 现在,如果你这样做了,你将有一个 HTTP 实现 约 10 微秒延迟(NB 数字从空气中提取,没有实际的基准测试 执行)。当然,具体的协议实现还是应该 注意可能影响延迟的事情,例如编码和 解码效率、内存分配等。
就低延迟空间而言,缺少的主要内容 来自 Asio 和 Networking TS 的有:
批处理数据报系统调用(即 sendmmsg、recvmmsg)。
某些套接字选项。
这些不包括在内,因为它们(目前)是特定于操作系统的,并且 不是 POSIX 的一部分。然而,Asio 和 Networking TS 确实提供了一个 以 native_*() 函数和 “可扩展”类型要求。
干杯,克里斯
【讨论】:
这似乎应该是您其他答案的一部分,而不是单独的答案。 谢谢!如果有人对命令和设备的具体示例中的“Spin, Pin and Drop-In”技术感兴趣alexeyab.com/2017/04/the-fastest-interconnect-for-hundreds.html【参考方案2】:几年前,我评估了 Boost Asio 在高频交易中的应用。据我所知,今天的基础知识仍然相同。以下是我决定不使用它的一些原因:
-
Asio 依赖于
bind()
风格的回调。这里有一些开销。
目前尚不清楚如何安排某些低级操作在正确的时刻或以正确的方式发生。
在一个非常重要的优化领域中有相当多的复杂代码。为特定用例优化复杂的通用代码更加困难。认为您不需要深入了解是错误的。
在 HFT 应用程序中几乎不需要可移植性。特别是,“自动”选择多路复用机制与使命背道而驰,因为必须单独测试和优化每个机制——这会增加而不是减少工作量。
如果要使用第三方库,libev
、libevent
和 libuv
等其他库则更加久经沙场,可以避免其中一些缺点。
相关:C++ Socket Server - Unable to saturate CPU
【讨论】:
我可以看到积分。 5. 和(有点)4. 关于 2. 我同意结合自定义处理程序类型正确处理股线。这就是你所说的“以正确的方式”吗?我真的不明白 (1.) 如何需要绑定样式回调,更不用说通过异步完成可以避免最小开销的地方了。 (3。)您是指库代码还是调用代码?也许你有一个令人信服的例子? @sehe:我没有使用 Boost.Asio 的示例代码——当我们意识到它不起作用时,我们放弃了用它构建的原型。那时libuv
是不可行的,但libev
和libevent
是——我们仍然选择走自己的路。我所说的“以正确的方式”的一些意思是需要(a)在特定时间使用特定的 sockopts/ioctl,(b)完全控制多个连接的优先级(包括故意饥饿),以及(c)使用特定的、不可移植的 API,例如 accept4()
(即使在今天,Asio 也没有使用,因此不能做原子的 SOCK_CLOEXEC
)。
啊。您所说的“以正确的方式”是指与外部要求有关(我以为您的意思是“为 Asio”)。 Atomic SOCK_CLOEXEC 是我遇到并不得不解决的问题之一。我不希望有任何示例 代码,只是像这样的示例可以用抽象的项目符号文本阐明您所想到的 场景 :)
饥饿确实是个问题。事实上,我讨厌我无法控制处理程序队列深度(没有花哨的扩展或中间排队——这将是很多开销)。 FWIW 我很少(从不?)将绑定与 Asio 一起使用。我没有看到(非教程级别)文档有很多建议。当你看例如示例组合操作,这些通常是专用的处理程序类型,我认为这也不会产生任何开销。
@Alex:是的,SOCK_CLOEXEC
问题与您的链接中描述的问题相同。您显示的解决方法代码有点好,但不是原子的,因此在某些多线程应用程序中不安全。以上是关于Boost ASIO 可以用来构建低延迟的应用程序吗?的主要内容,如果未能解决你的问题,请参考以下文章