2. 网卡硬件架构:深入理解网卡内部结构(MAC、PHY、DMA、Ring Buffer)

大家好,我是你们的老朋友。今天咱们聊聊网卡内部到底长什么样。

很多人调优网卡,上来就改中断合并、调缓冲区大小。但说实话,你不懂网卡内部怎么工作的,调优就是瞎蒙。我见过太多工程师,把Ring Buffer改得巨大,结果延迟反而飙升——这就是典型的“知其然不知其所以然”。

好,咱们今天就把网卡扒开看看。核心就四个组件:MAC、PHY、DMA、Ring Buffer。搞懂它们,你就掌握了网卡调优的底层逻辑。

2.1 网卡的整体架构:一张图看懂

先看一张我手绘的架构图。别嫌丑,这图我用了十年,每次培训都拿它开场。

主机内存 (Host Memory) Ring Buffer (TX/RX) 数据包描述符 Socket 缓冲区 PCIe 总线 网卡芯片 (NIC) DMA 引擎 数据搬运工 MAC 层 帧控制/过滤 PHY 层 信号编码/解码 网线 数据流向:主机内存 → PCIe → DMA → MAC → PHY → 网线 接收方向则完全相反

数据流其实很简单:发数据时,从内存经PCIe到DMA,再到MAC和PHY,最后从网线出去。收数据就是反过来。但每个环节都有坑,咱们一个一个说。

2.2 PHY 层:物理层的“翻译官”

PHY,全称Physical Layer,物理层。它的工作说白了就是把数字信号变成能在网线上传输的模拟信号,反过来也一样。

我记得有一次排查一个丢包问题,抓包显示一切正常,但就是丢包。折腾了两天,最后发现是PHY芯片的信号衰减阈值设置得太保守了。换了个参数,问题解决。嗯,这种坑,没经验真想不到。

PHY层有几个关键参数你得知道:

  • 速率协商:自动协商(Auto-Negotiation)是PHY层的核心功能。两端网卡协商出共同支持的最高速率。我建议你永远不要关闭自动协商,除非你明确知道自己在做什么。强制设置速率经常导致协商失败,链路时断时续。
  • MDI/MDIX:自动翻转线序。现在的PHY基本都支持,但老设备上可能是个坑。
  • EEE (Energy Efficient Ethernet):节能以太网。省电,但会引入额外的延迟。服务器场景下我一般建议关掉。
我的经验:排查物理层问题,先看 ethtool eth0 的输出。重点关注 SpeedDuplexLink detected 三个字段。如果显示 Speed: Unknown! 或者 Duplex: Half,那基本就是PHY层出问题了。

2.3 MAC 层:帧的“交通警察”

MAC层,Media Access Control,媒体访问控制。它负责封装和解封装以太网帧,还管着谁什么时候能发数据。

MAC层干的事包括:

  • 帧封装:加上源MAC、目的MAC、类型字段,尾部还有FCS(帧校验序列)。
  • 地址过滤:检查收到的帧是不是发给自己的。不是?直接扔掉。
  • 流量控制:支持Pause帧,让对端“慢点发”。但说实话,我一般不建议在服务器上开Pause帧。它会导致连锁反应,一个端口堵了,整台交换机都受影响。
  • 校验和卸载:很多网卡支持硬件计算IP/TCP校验和,减轻CPU负担。

这里有个常见的误区:很多人以为MAC地址是写在网卡ROM里的,永远不变。其实现代网卡的MAC地址是可以改的,通过驱动或者ethtool就能操作。当然,生产环境我不建议你乱改,除非有特殊需求。

2.4 DMA:数据搬运的“隐形冠军”

DMA,Direct Memory Access,直接内存访问。这是网卡性能的关键所在。

没有DMA的时代,CPU得亲自把网卡的数据搬到内存里。你想想看,CPU本来要处理业务逻辑,结果还得干搬运工的活,效率能高吗?

DMA的出现,让网卡可以直接读写主机内存,CPU只需要在开始和结束时打个招呼就行。 这就像你请了个搬家公司,自己只需要在门口指挥一下。

DMA相关的调优参数:

参数 说明 我的建议
DMA 通道数 网卡使用的DMA通道数量 多队列网卡一般自动分配,不用手动改
DMA 缓冲区大小 每次DMA传输的数据量 默认值通常够用,除非你跑特殊应用
DMA 对齐 数据在内存中的对齐方式 不对齐会导致性能下降,驱动一般会处理好
注意:我曾经遇到过一个案例,某款网卡在特定主板上频繁丢包。查到最后发现是DMA地址映射出了问题——网卡和主板BIOS的DMA重映射功能不兼容。解决办法是更新BIOS或者关闭IOMMU。这种问题,不遇到一次你根本想不到。

2.5 Ring Buffer:数据包的“中转站”

Ring Buffer,环形缓冲区。这是网卡和驱动之间交换数据的核心数据结构

你可以把它想象成一个环形队列。网卡收到数据包,就往Ring Buffer里放一个“描述符”,告诉驱动“数据在内存的某某地址,快来取”。驱动处理完,再把描述符还给网卡,循环使用。

Ring Buffer有两个:

  • RX Ring:接收方向。网卡往里写,驱动从中读。
  • TX Ring:发送方向。驱动往里写,网卡从中读。

Ring Buffer的大小直接影响性能:

  • 太小:网卡收包太快,Ring Buffer满了,新包直接丢弃。这就是传说中的Ring Buffer溢出丢包
  • 太大:每个包在Ring Buffer里排队时间变长,延迟增加。而且占用更多内存。

怎么查Ring Buffer大小?用 ethtool -g eth0

# ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX:             4096
RX Mini:        0
RX Jumbo:       0
TX:             4096
Current hardware settings:
RX:             256
RX Mini:        0
RX Jumbo:       0
TX:             256

看到没?最大支持4096,当前只用了256。如果你的服务器丢包率很高,可以试着调大:

ethtool -G eth0 rx 1024 tx 1024
避坑指南:我曾经把Ring Buffer调到最大(4096),结果延迟从50微秒飙到了200微秒。为什么?因为包在缓冲区里排队时间变长了。所以不是越大越好。我的习惯是:先设成1024,观察丢包率和延迟,再微调。如果丢包率已经很低了,就别动了。

2.6 多队列:让多个CPU一起干活

现代网卡都支持多队列(Multi-Queue)。简单说,就是网卡内部有多个DMA通道和多个Ring Buffer,每个队列可以绑定到不同的CPU核心上。

这样做的好处很明显:

  • 并行处理:多个CPU核心同时处理网络包,吞吐量翻倍。
  • 避免锁竞争:每个队列独立,不需要抢锁。
  • CPU亲和性:同一个流的包始终由同一个CPU处理,缓存命中率高。

查看网卡支持多少队列:

# ls /sys/class/net/eth0/queues/
rx-0  rx-1  rx-2  rx-3  tx-0  tx-1  tx-2  tx-3

这里有4个RX队列和4个TX队列。如果你的网卡只有1个队列,那说明它不支持多队列,或者驱动没开。

多队列的调优,核心是让每个队列绑定到不同的CPU核心,并且让中断也分散到不同核心。这部分内容,咱们后面章节会详细讲。

2.7 硬件卸载:把活交给网卡干

网卡除了搬数据,还能干不少“脑力活”。这就是硬件卸载(Hardware Offloading)

常见的卸载功能:

  • TSO (TCP Segmentation Offload):TCP分段卸载。发送大块数据时,网卡自己把它切成MTU大小的段,CPU不用管。
  • GSO (Generic Segmentation Offload):通用分段卸载。比TSO更灵活,支持多种协议。
  • LRO (Large Receive Offload) / GRO (Generic Receive Offload):接收端合并。把多个小包合并成大包,减少CPU处理次数。
  • RSS (Receive Side Scaling):接收端缩放。根据哈希值把包分发到不同队列,实现负载均衡。
  • VXLAN/GENEVE 卸载:隧道协议卸载。虚拟化场景下特别有用。

查看当前卸载状态:

# ethtool -k eth0
Features for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: on
tcp-segmentation-offload: on
udp-fragmentation-offload: off
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: on
注意:硬件卸载不是万能的。我遇到过一个问题:开了TSO后,某款防火墙设备处理不了大包,导致连接中断。排查了半天,最后关掉TSO就好了。所以在特殊网络环境下(比如经过某些中间设备),关掉卸载功能反而更稳定

2.8 总结:一张表记住核心组件

组件 位置 核心功能 调优关注点
PHY 物理层 信号编码/解码、速率协商 自动协商、EEE开关
MAC 数据链路层 帧封装/过滤、流量控制 Pause帧、校验和卸载
DMA 总线接口 数据搬运、内存访问 通道数、缓冲区大小
Ring Buffer 驱动层 数据包中转、描述符管理 大小设置、溢出监控
多队列 网卡内部 并行处理、负载均衡 队列数、CPU亲和性
硬件卸载 网卡功能 TSO/GRO/RSS等 按需开启/关闭

好了,网卡的硬件架构就聊到这儿。搞懂了这些底层组件,你再去调优,心里就有谱了。下一节咱们会深入Ring Buffer的监控和调优实战,到时候我会手把手教你用工具定位问题。


专注资料整理