FPGA 专家 32:超低延迟设计——和每一纳秒、每一纳秒抖动作战
本文是
fpga/专家层第 35 篇。流水线/反压基础见 进阶 15,网络线速管线见 专家 32,确定性网络见 专家 36。
一、延迟预算:逐段纳秒账

光模块/SerDes → PCS/MAC → 头解析 → 业务(解码/策略/风控) → 编码 → 仲裁 → SerDes
固定延迟(优化对象) + 排队/仲裁/软件(抖动来源,必须消灭)优化目标不是平均延迟,而是最大延迟与尾部抖动。
二、确定性六原则

- cut-through:头字段到齐即开始,边收边算边发。
- 热路径无共享:不碰 DDR/总线/中断/CPU,全片上单周期存储。
- 固定深度流水线:不允许动态停顿。
- 无分支电路:并行比较 + MUX 选择,替代条件跳转。
- 去突发:按可持续速率设计;超限丢旧/覆盖,不排队。
- 关键流专用:自己的订单/控制帧走绝对优先通路。
三、实现层技巧

| 手段 | 作用 |
|---|---|
| Pblock + 锁引脚(贴近收发器) | 布线短、结果可复现 |
| 局部高速时钟域 | 压缩热路径周期数 |
| flatten、复制大扇出、禁意外 retiming | 减逻辑级、稳定时序 |
| 低延迟 SerDes 模式、减弹性缓冲 | 省物理层纳秒 |
| 报文模板预生成,运行时只填字段 | 发送侧省拍 |
| 硬件时间戳入/出口 | 测准真实延迟 |
四、金融交易场景要点
行情(FAST/逐字段流式解压)→ 策略状态机 → 合规风控并行前置 → 订单模板填入 → 线速发送;主机配合 kernel-bypass 栈,但真正的决策闭环全在 FPGA。报告指标用硬件直方图(P50/P99/P99.9/Max/jitter)。
五、逐段延迟账本:从报文进 PHY 到主机可见

低延迟设计的第一步不是优化,而是建立一份纳秒级的延迟预算表,把端到端路径切成可独立核算的段,避免对着一个总耗时拍脑袋。以一条“报文从光纤进入 FPGA、处理、再发出/通知主机”的路径为例,典型段落包括:PHY/SerDes 串并转换与对齐(若干并行周期,与位宽和编码有关)、PCS/PMA 与 FEC(若启用,FEC 是大块延迟,可达数百纳秒到微秒级,低延迟场景常关 FEC 或用低延迟 FEC)、MAC 层帧处理、报文头解析、表查找(片上 BRAM/TCAM 几拍 vs 外部 DDR 上百拍,这是软件/慢路径与硬件快路径的分水岭)、决策与报文修改、输出仲裁与排队(排队延迟是负载相关的大头)、SerDes 发送,以及若要通知主机的 DMA 写入、中断/轮询、主机用户态读到的时间。每一段都标注典型值和最坏值,区分固定延迟(与负载无关、可预测)和可变延迟(排队、仲裁、等待慢介质)。
固定延迟与可变延迟要分开管理。流水线级数带来的是固定延迟,增加几级流水通常不影响吞吐和确定性,最坏值等于典型值,这类延迟好预算;真正可怕的是可变延迟:FIFO 排队、与其他主设备争用 DDR/总线、中断响应、主机调度、缓存缺失,它们的最坏值可能是典型值的几十上百倍且难以预测。低延迟架构的核心努力,就是把可变延迟逐出快路径——查表全放片上、热路径不经过 DDR/PCIe 往返、输出端口给关键流量保留专用队列或严格优先级、主机通知用轮询而非中断、主机侧绑核并隔离(isolcpus、无中断、无调度迁移)。做完这些,端到端延迟分布才会从“长尾失控”变成“集中在一个可签合同的窄区间”。
cut-through 与位宽/频率的取舍直接决定基础延迟。store-and-forward 收齐整帧再转发,延迟等于帧时长;cut-through 收到头够做决策就转发,把延迟压到头部处理时间。在极致场景里,还要最小化并行度带来的序列化延迟:更宽的内部总线 + 更高时钟能让一个 beat 承载更多字节、减少“等数据攒够一拍”的时间,但宽总线可能压低频率反而增加每拍时间,需要联合优化。甚至要审视编码:64b/66b、64b/67b、FEC 等链路编码都有固有块延迟,协议选项本身就是延迟预算的一部分。
主机侧的尾巴常被 FPGA 团队忽略,却可能是最大头。FPGA 算完写 DDR 再中断、内核唤醒、上下文切换到用户态,轻易就是 1~10 微秒且抖动巨大;kernel bypass(DPDK 式用户态轮询完成队列、DMA 直接写用户态预注册内存、专用核自旋等待)能把这一段压到亚微秒且几乎无抖动,代价是独占 CPU 核。要把“数据在 FPGA 里很快、但主机 10 微秒后才看到”的系统算账算清楚——很多所谓 FPGA 低延迟方案的实际收益被软件尾巴吃光。是否走内核、是否零拷贝、用中断还是轮询、绑核和电源管理(关闭 C-state、固定 P-state)都应写进延迟预算表并用实测填充,而不是只测 FPGA 段自嗨。
六、确定性的工程化:让最坏值可证明、可测量、可签合同
低延迟有两个常被混为一谈的目标:低均值/中位数和低尾延迟(P99/P99.9/最大值)。交易、控制、精密测量等场景真正付费买的是后者——一个平均 500ns 但偶尔 50μs 的通路,比稳定 800ns 的通路危险得多。因此工程重点是让延迟分布尽可能窄、最坏值可分析,并能在出厂和运行期被证明。
排除抖动源是确定性的主线。逐一识别并处理:①排队——关键流走无排队或有界深度的专用队列,严格优先级保证它不被背景流量阻塞,队列深度按最坏突发设计且明确丢包策略(宁可丢也不无界等待);②资源争用——快路径用独立的存储 bank、独立总线、独立端口,不与统计、日志、控制面共享会停顿的资源;③中断与软件——快路径完全轮询化、不依赖中断和操作系统调度;④动态行为——避免在快路径上做动态内存分配、动态仲裁、动态长度的复杂操作,一切时间可静态推出;⑤时钟相关——用单一快时钟域或设计有界的跨时钟 FIFO,避免 CDC 引入的不定等待。把所有“取决于当下忙不忙”的因素从路径上拿掉,剩下的才是可签合同的延迟。
有界性比平均值更重要。对每个缓冲都要回答“最多排多久”,而不是“平均排多久”:FIFO 深度由生产/消费速率差和最大突发按最坏情况算出,并给出满时行为(反压到哪、丢谁、是否标记);仲裁器用加权/严格优先级并能证明高优先级流的最大等待;表查找用固定级数的流水/TCAM,延迟固定;任何“等软件响应”的握手都要有硬件超时和降级。设计评审时,对路径上每个模块索要“最坏延迟 + 推导依据”,串起来就是系统最坏延迟。无法给出上界的模块(通用 CPU、DDR 随机访问、PCIe 重读)不允许出现在承诺低延迟的路径上。
测量体系与设计同等重要,因为无法测量就无法签合同。硬件侧应内置高精度时间戳:在报文进入的第一拍打进入时间戳、离开时打离开时间戳(用同一全局时钟,最好支持 IEEE 1588/PTP 纳秒级时基),把逐段或端到端延迟随报文镜像/统计导出;在线维护延迟直方图(分桶计数)而非只记平均,这样能持续看到 P99/P99.9 和长尾。测试要覆盖最坏负载组合:满背景流量打满所有端口、突发小帧、表查找压力、DDR 繁忙、控制面操作(更新表项、读统计)并发进行时,关键流的尾延迟仍要满足指标。只在空闲环境测“裸延迟”是自欺欺人。还要做温度/电压/器件批次的 corner 测试,因为慢 corner 下固定延迟也会上升。
把延迟指标变成合同和回归项。定义明确的 SLA:在规定背景负载和报文混合下,关键流的延迟均值、P99、最大值各是多少,以什么时基、在哪两个物理点之间测量。把这套测量自动化进回归(见 专家 39 的硬件 CI),每次改 RTL 都跑一遍延迟直方图,任何把尾延迟推过红线的提交立即拦下。很多团队功能和吞吐有回归、延迟没有,结果几个月后没人说得清系统现在的最坏延迟是多少——对低延迟产品,这等于核心指标失控。
七、实现层技巧:电路层面的纳秒争夺
在架构把可变延迟逐出之后,剩下的固定延迟要靠电路与微架构技巧一纳秒一纳秒地抠。这些技巧各自收益不大,但叠加起来可能决定一个方案是 400ns 还是 800ns。
时钟频率与位宽的联合优化。提高频率直接降低每拍时间,但受限于关键路径和 SerDes 参考时钟;加宽大位宽能提高吞吐却可能因布线和多路选择拉长关键路径、反而降频。正确做法是让数据通路上的组合逻辑深度与目标频率匹配:重逻辑(复杂查找、大加法树、长 mux)切更多流水级,把每拍做的事减到最少;对真正的热点手工规划布局(把紧耦合的解析/查找/决策逻辑约束在相邻区域),减少布线延迟——在高速设计里布线延迟往往超过逻辑延迟。不要无脑追求最高综合频率,而要在“频率 × 数据位宽”满足线速的前提下,使头部关键路径上的级数最少,因为延迟等于级数除以频率,级数减半哪怕频率略降也可能更快。
把慢操作移出快路径。任何需要多周期的操作都不能阻塞直通流:大规模转发放小容量片上缓存(常用表项驻留),未命中送慢路径/预测转发;统计计数器用批量回写(先在片上累加,定期刷 DDR),绝不为记账停报文;日志、镜像、控制命令全走独立通道和队列。解析和查表尽量并行化:报文头一到就并行展开所有可能字段、并行发起多张表查找,再用选择器组合结果,用空间换串行级数。决策结果若可预测,可用推测(speculation):先按最可能的结果启动动作,确认后再提交/撤销,掩盖查表延迟。
仲裁、队列与内存系统的低延迟配置。给关键流设严格优先级或专用通路,避免它在公平仲裁里排队;输出端最小化 FIFO 深度并保证关键流永远先服务(代价是背景流可能被饿死,要明确这是有意的策略)。片上存储选延迟确定的分布式 RAM/BRAM 而非 URAM/DDR 存热表;BRAM 配置成单周期读、避免读改写;双口/多口 RAM 支持并行查找。跨时钟域只在边界发生且用有深度的异步 FIFO,把 CDC 延迟计入预算,快路径内部尽量单时钟域。物理层选择低延迟模式:关 FEC 或用低延迟 FEC、关不必要的编码/扰码选项、选择 cut-through 的 MAC/PCS 配置并核对厂商 IP 的延迟参数(很多 IP 默认配置为吞吐/可靠性优化,延迟并非最低)。
主机与软件路径的极致化。用户态驱动、预注册并 pin 住的 DMA 缓冲、描述符和完成队列映射到用户态、专用核自旋轮询,是把主机尾延迟压到亚微秒的标准组合;运行时关闭该核的中断、调度、地址空间随机化带来的 TLB 抖动,使用大页降低 TLB miss,锁死 CPU 频率、禁用深度 C-state。FPGA 侧用 DMA 直接写主机预分配内存并在数据末尾写一个“完成标志/序号”,轮询核只见一次内存读即知就绪,省掉中断。时间戳在 FPGA 内打、随数据一起给主机,避免主机时钟和读时间误差污染测量。最后保持收益的边际意识:先用延迟账本定位最大的几段(往往是排队、FEC、主机软件,而不是某级组合逻辑),把精力花在占比最大的段上;把一个 5μs 的 FEC 关掉,胜过把 300ns 的电路优化到 250ns。
八、金融交易场景:为什么 FPGA 是 tick-to-trade 的标配
高频/低延迟交易是 FPGA 低延迟能力最被严格检验的领域,理解这个极端场景的需求,能反哺一切确定性设计。交易系统的核心指标是 tick-to-trade 延迟:从市场行情报文(tick)的第一个比特进入网卡,到 FPGA/主机解析行情、依据策略更新订单簿/产生信号、做出下单/撤单决策、再把订单报文送上线缆,全程的时间及其抖动。市场是严格的时间优先竞争,更快且更稳定的参与者在流动性提供中占优;而 FPGA 把传统“网卡→内核→用户态进程→策略→内核→网卡”的几微秒到几十微秒、抖动巨大的路径,压缩到几百纳秒、抖动几十纳秒,因此成为顶级做市和低延迟策略的事实标准。
为什么必须在 FPGA 内做决策,而不只是“FPGA 收包 + CPU 算”。哪怕用 kernel bypass 把主机路径压到亚微秒,一次 FPGA→CPU→FPGA 的往返仍引入纳秒到微秒级且受 CPU 抖动影响的延迟;极致策略把整条快路径——行情解析、协议解码、订单簿更新(撮合簿本身用片上 RAM 组织成可每拍更新/查询的结构)、风控的硬阈值检查、订单生成与协议编码——全部做成 FPGA 内的固定流水线,CPU 完全退出 tick-to-trade 关键路径,只负责配置参数、加载策略、监控和慢路径(如非关键消息、收盘处理)。这正是“快路径硬件、慢路径软件”原则最纯粹的体现(通用方法论见 专家 31)。
确定性和公平性在交易场景被放大到极致。不仅要快,还要可复现:同一行情序列在相同状态下必须产生相同决策和相同延迟,否则策略回测与实盘不一致、难以归因;尾延迟决定最坏情况下的成交质量,一个偶发抖动可能让一批订单滑点。因此系统追求无排队或有界排队、无中断、无软件介入快路径、全局纳秒时基(PTP 锁相到交易所时钟),并对每个决策附带精确时间戳用于合规与复盘。风控(pre-trade risk)也必须在下单前的硬件路径上强制执行(最大下单量、价格范围、净头寸、自成交防护),既满足监管要求又不显著增加延迟——风控做成并行检查、不通过即拦截,而不是事后审计。
工程上的特殊约束:行情协议往往是组播 UDP、小包、突发尖峰(开盘/收盘/波动事件时 PPS 暴增),系统必须按最坏突发率线速解析不丢包;多个交易所/多条链路要并行接收并做时钟对齐和序列仲裁;订单簿更新与查询在同一拍可能冲突,存储结构要专门设计;可靠性要求极高(交易时段宕机即真金白银损失),需要冗余(双 FPGA/双链路热备、状态复制、故障时确定性切换)和完善的健康监控。配置更新(风控参数、交易开关、策略表)要能在不停快路径的情况下安全生效(原子更新、版本号),并支持一键 kill switch(硬件级撤单/停发)。
可借鉴的方法论并不只属于金融业:①把端到端关键路径整体下沉为有界流水线,把通用计算推到慢路径;②用纳秒时基和逐事件时间戳让每个决策可测量、可复盘、可签 SLA;③按最坏突发而非平均负载设计;④安全/风控/合规检查并行内建而非串行追加;⑤冗余和确定性切换作为架构的一部分。凡对实时性、确定性、可观测性有高要求的场景(工业控制闭环、精密测量、5G 前端、自适应光学、实时防护),都能从这套思路受益——差别只在延迟目标的数量级,而“逐段预算、逐出可变、有界可测、快慢分离”的纪律完全一致。
九、典型坑与低延迟验收清单
低延迟项目的失败模式高度集中,汇总如下并给出可执行的验收清单。
只看均值不看长尾:报“平均延迟”而回避 P99/最大值,在客户的背景负载下偶发抖动被抓。正解是以 P99/P99.9/最大值为设计和验收指标,用硬件时间戳直方图在最坏负载下测量。
快路径混入慢介质/软件:片上放不下的表走 DDR、统计写 DDR 阻塞、关键决策等主机、用中断通知,引入不可控长尾。正解是热表热状态全片上、旁路统计、主机退出关键路径、快路径轮询化。
store-and-forward / FEC / 默认 IP 配置:整帧缓存、开启 FEC、使用吞吐优先的 MAC/PCS 默认参数,基础延迟白白抬高几百纳秒到微秒。正解是 cut-through、低延迟 FEC/关 FEC、核对并选择 IP 的最低延迟配置,写进预算。
队列无界、仲裁“公平”:关键流和背景流在同一个公平队列里竞争,拥塞时尾延迟爆炸。正解是关键流严格优先级/专用有界队列,明确满队列行为(丢背景保关键)。
主机尾巴吃掉收益:FPGA 很快,但 DMA+中断+内核+调度到用户态已数微秒。正解是 kernel bypass、用户态轮询、pin/绑核/大页/锁频/关 C-state,并把主机段纳入端到端预算实测。
只在空载测试:空闲时测裸延迟,满载和控制面并发时完全两回事。正解是满背景流量 + 突发小帧 + 表项更新/统计读取并发的 corner 矩阵压测。
没有时基/无法逐段归因:出了尾延迟问题不知在哪一段。正解是统一 PTP 级全局时基,进出口和关键段打时间戳,在线延迟直方图并纳入回归。
为省资源牺牲确定性:共享总线/动态仲裁/多周期操作放在快路径省了 LUT,却引入不定等待。正解是关键路径资源专用、一切延迟可静态推出、无界等待模块不得入快路径。
低延迟验收清单:①有逐段纳秒预算表,区分固定/可变延迟,总最坏值满足 SLA;②快路径无 DDR/主机/中断依赖,热表全片上;③cut-through、低延迟链路配置确认;④关键流有严格优先级和有界队列,满时行为明确;⑤主机 kernel bypass、绑核、锁频、大页配置到位并实测;⑥全局 PTP 时基,进/出口时间戳、在线 P99/最大值直方图;⑦在满背景负载、突发、控制面并发、温度/电压 corner 下尾延迟达标;⑧风控/安全检查并行内建、有 kill switch;⑨冗余/热备与确定性切换验证;⑩延迟直方图自动化进每次 RTL 回归并设红线。把这十项作为低延迟产品的出厂门槛,才能交付“最坏也够快”而不是“平均很快”的系统。
十、确定性软件栈:当 FPGA 必须和主机协同时的尾延迟治理

许多低延迟系统里,FPGA 负责硬件快路径,但事件最终仍要交给主机(做风控判断、写日志、与策略进程通信),这时主机软件会成为尾延迟的新主导项,前面在电路上省下的几百纳秒可能被一次上下文调度全部吞掉。确定性软件栈的目标,是让主机侧的关键线程也具备可分析的延迟上界,方法和硬件同构:识别抖动源、逐出关键路径、为剩余等待设界。
关键线程的环境隔离:把处理核从内核调度器手里“赎身”——用专用 CPU 亲和性绑定(affinity),配合内核启动参数把这些核从通用调度和内核卸载任务中隔离(isolcpus/nohz_full/rcu_nocbs),中断路由到其他核(IRQ 亲和性),关键线程提升为实时策略且锁内存(mlockall,杜绝缺页)。电源管理全部固定:禁用 C-state、锁 P-state/主频,因为一次深睡唤醒就是几十微秒的抖动。硬件上让 FPGA 的完成事件走 MSI-X 直送绑定核、用用户态轮询而非中断(或仅在无任务时由中断兜底),DMA 缓冲预注册、零拷贝。做完这些,主机侧事件响应可压到亚微秒且分布很窄。
软件结构上去抖动:关键路径不做内存分配(预分配对象池/无锁环形队列)、不上锁或只用自旋无锁结构(避免被调度走还持有锁)、不打同步日志(日志写共享无锁缓冲由后台线程刷盘)、不碰文件系统/网络栈这类不可预测路径;系统调用减到最少,或用内核旁路用户态框架。批处理与延迟的矛盾用“自适应”处理:低负载立即提交(最低延迟),高负载才聚合(保吞吐),切换阈值和最坏延迟一起设计。时间测量用 TSC/硬件计数器,关键操作打点在线生成延迟直方图,使尾延迟成为持续可见的线上指标(与 专家 39 的硬件 CI 遥测一致)。
协同边界的契约:FPGA 与主机之间要约定什么是硬实时(硬件保证)、什么是软实时(软件尽力),不要让业务依赖“主机在 X 微秒内必响应”——凡是上界必须保证的动作(安全联锁、超时熔断、kill switch)都在 FPGA 内闭环;主机只负责可容忍毫秒级抖动的决策和监督。主机看门狗与硬件看门狗分层:软件心跳喂硬件狗,软件停摆时硬件进入安全态。这样即使软件栈做不到严格硬实时,整个系统的安全与正确性仍由有界的硬件路径兜底。
十一、典型系统的延迟预算分解:三个参照案例
把原则落到具体数字上,建立数量级直觉。案例一高频行情处理 + 自动决策(tick-to-trade 量级):SerDes/PCS 约几十至上百纳秒、MAC 与报文头解析数拍(按 300MHz 约十几到几十纳秒)、表查找(片上 BRAM/TCAM 式)数拍、决策流水数拍、报文生成与 SerDes 再数十纳秒,FPGA 内总计常见数百纳秒;若经主机 kernel bypass 约再加一微秒上下,走内核则跳到数微秒至数十微秒且无界。预算控制重点是关 FEC、cut-through、全片上查找、决策不下主机。
案例二工业实时闭环(EtherCAT/TSN 类毫秒级周期):单周期预算常为 31.25μs/125μs/1ms 级,链路传播、从站处理、主站计算都在预算内,余量用于抖动和重试。FPGA 在这里通常承担从站 ESC/从控制器或 TSN 桥,关键是中断响应与处理的最坏时间落在周期的一小部分、网络调度窗(见 专家 36)与本地控制周期对齐,余量不足时把运动控制内环下沉硬件。数字上宽裕,但确定性(绝不超时)比平均快更重要,预算用最坏情况做满。
案例三低延迟采集/测量(ADC 流到结果):ADC JESD/LVDS 解串与帧对齐数十到上百纳秒、数字下变频/滤波按流水级数(每级一个时钟周期)、判决与时间戳同拍、经 PCIe 上送主机则受 DMA 批量与 TLP 延迟影响(数百纳秒到微秒级)。若只需触发本地响应,把阈值判决和时标留在 FPGA(纳秒级),主机只收摘要;若必须上送,用小块高频 DMA 或 P2P 直写对端设备避免主机参与。
三个案例的共同方法是逐段列预算、标注固定/可变、把可变段重设计或移出关键路径、再用硬件时间戳实测 P99/最大。新手用总吞吐反推延迟,专家直接为最坏路径做加法——这就是低延迟工程与普通性能工程的分野。
总结
超低延迟设计把"排队、缓冲、批处理、共享、软件"全部当成敌人:cut-through 固定流水线 + 热路径片上专用 + Pblock 贴近收发器 + 用丢包代替排队,并用硬件时间戳直方图对尾部延迟负责。