3、网卡基础回顾:网卡架构、MAC层、PHY层、PCIe接口、DMA引擎、中断机制
各位同学,咱们今天聊聊网卡。别觉得基础,我做了这么多年低延迟交易系统,发现很多问题都出在对网卡的理解不够深。说白了,网卡就是FPGA和外部网络之间的桥梁,这座桥要是搭不好,你FPGA处理得再快也没用。
3.1 网卡整体架构
先看一张整体图,我习惯把网卡分成三个层次来看:
这张图我画了很多次了。从上往下看,数据从FPGA或CPU出发,经过PCIe和DMA,到达MAC层做帧处理,再到PHY层做信号转换,最后通过网线发出去。反过来就是接收路径。
核心要点:在低延迟交易中,我们最关心的是数据从网线到FPGA逻辑的路径有多短。每一层都会引入延迟,所以很多高端网卡允许FPGA直接接管MAC和PHY的控制权。
3.2 MAC层
MAC层,全称是Media Access Control。它干的事说白了就是三件:
- 帧封装与解封装:给数据包加上MAC头尾,或者反过来拆掉
- CRC校验:检查数据在传输过程中有没有出错
- 流量控制:防止发送方太快,接收方来不及处理
我记得有一次做项目,发现收到的数据包偶尔会丢几个字节。查了半天,最后发现是MAC层的CRC校验没通过,网卡直接把包扔了。嗯,这里要注意,很多低延迟场景下我们会关闭MAC层的某些功能,比如流量控制,因为那会增加不确定的等待时间。
实战技巧:在FPGA中实现MAC层时,我个人习惯把CRC校验放在最后一级流水线。这样即使校验失败,前面的处理也不会被阻塞,适合流水线式的数据处理。
3.3 PHY层
PHY层是物理层,它负责把数字信号变成模拟信号,或者反过来。你想想看,网线里传的是电信号或者光信号,不是0和1。PHY层做的就是这件事。
PHY层的关键参数有:
| 参数 | 说明 | 低延迟关注点 |
|---|---|---|
| 速率 | 10M/100M/1G/10G/25G/100G | 越高越好,但功耗也高 |
| 编码方式 | 8B/10B, 64B/66B, 128B/130B | 编码效率影响有效带宽 |
| 串并转换 | SERDES | 延迟通常在几纳秒到几十纳秒 |
| 自动协商 | Auto-negotiation | 建议关闭,固定速率减少延迟 |
我曾经踩过一个坑:某款网卡的PHY层默认开启了自动协商,结果每次链路重连都要花2-3秒。在交易系统里,2秒意味着什么?可能几十万笔订单就错过了。所以我的建议是:固定速率,关闭自动协商。
3.4 PCIe接口
PCIe是网卡和主机通信的高速通道。在低延迟交易中,PCIe的延迟直接影响数据从网卡到CPU或FPGA的速度。
PCIe的几个关键概念:
- Lane(通道):每个Lane是一对差分信号,x1、x4、x8、x16表示通道数
- Gen(代):Gen1=2.5GT/s, Gen2=5GT/s, Gen3=8GT/s, Gen4=16GT/s, Gen5=32GT/s
- TLP(事务层包):PCIe通信的基本单位
注意:PCIe的延迟不仅仅是物理传输延迟,还包括协议开销。比如一次DMA读操作,需要先发送读请求,等待返回数据。这个往返时间在几百纳秒到几微秒之间。在FPGA设计中,我通常会用写操作代替读操作来减少延迟。
3.5 DMA引擎
DMA,Direct Memory Access。它的作用是不经过CPU,直接把网卡的数据搬到内存里。你想想看,如果没有DMA,每个数据包都要CPU去读,那CPU就别干别的了。
DMA的工作流程大致是这样的:
- 网卡收到数据包,存入内部缓冲区
- DMA引擎发起PCIe写操作,把数据写入主机内存
- 写入完成后,通知CPU或FPGA数据已就绪
在低延迟场景下,DMA的设计有几个关键点:
- 描述符环(Descriptor Ring):预分配的内存区域,避免动态分配
- 零拷贝(Zero Copy):数据直接从网卡到应用缓冲区,不经过内核
- 多队列(Multi-Queue):每个CPU核心一个队列,避免锁竞争
我的经验:在FPGA中实现DMA时,我习惯用寄存器映射的方式代替传统的描述符环。虽然灵活性差一些,但延迟可以降低30%以上。说白了,就是用空间换时间。
3.6 中断机制
中断是网卡通知主机数据到了的方式。传统的中断方式是:网卡发一个中断信号,CPU停下当前工作,去处理网卡数据。
但这种方式在高速网络下有问题——中断太多了,CPU光处理中断就忙不过来。所以有了这些优化:
- 中断合并(Interrupt Coalescing):攒几个包再发一次中断
- NAPI:Linux内核的轮询+中断混合机制
- 忙轮询(Busy Polling):CPU不断检查网卡状态,不用中断
在低延迟交易中,我们通常选择忙轮询。为什么?因为中断有不确定性。中断来了,CPU要保存上下文、跳转到中断处理函数、处理完再恢复。这个过程少说也要几微秒。而忙轮询虽然占用CPU,但延迟是确定的。
避坑指南:我曾经在一个项目里用了中断合并,结果发现延迟的抖动特别大。后来改成忙轮询,延迟从平均5微秒降到了1.2微秒,而且几乎没有抖动。所以,如果你的CPU核心够用,别犹豫,用轮询。
3.7 小结
好了,网卡的基础知识就回顾到这里。总结一下:
- 网卡架构分三层:应用层(PCIe+DMA)、MAC层、PHY层
- MAC层负责帧处理和CRC校验,低延迟场景可以精简
- PHY层负责信号转换,建议关闭自动协商
- PCIe接口是高速通道,用写操作代替读操作减少延迟
- DMA引擎实现数据直传,零拷贝和多队列是标配
- 中断机制在低延迟场景下建议用忙轮询
这些内容看起来基础,但每一个点在实际项目中都可能成为瓶颈。下一章我们会深入FPGA和网卡的协同设计,到时候这些基础知识都会用上。