2. 网卡硬件架构:深入理解网卡内部结构(MAC、PHY、DMA、Ring Buffer)
大家好,我是你们的老朋友。今天咱们聊聊网卡内部到底长什么样。
很多人调优网卡,上来就改中断合并、调缓冲区大小。但说实话,你不懂网卡内部怎么工作的,调优就是瞎蒙。我见过太多工程师,把Ring Buffer改得巨大,结果延迟反而飙升——这就是典型的“知其然不知其所以然”。
好,咱们今天就把网卡扒开看看。核心就四个组件:MAC、PHY、DMA、Ring Buffer。搞懂它们,你就掌握了网卡调优的底层逻辑。
2.1 网卡的整体架构:一张图看懂
先看一张我手绘的架构图。别嫌丑,这图我用了十年,每次培训都拿它开场。
数据流其实很简单:发数据时,从内存经PCIe到DMA,再到MAC和PHY,最后从网线出去。收数据就是反过来。但每个环节都有坑,咱们一个一个说。
2.2 PHY 层:物理层的“翻译官”
PHY,全称Physical Layer,物理层。它的工作说白了就是把数字信号变成能在网线上传输的模拟信号,反过来也一样。
我记得有一次排查一个丢包问题,抓包显示一切正常,但就是丢包。折腾了两天,最后发现是PHY芯片的信号衰减阈值设置得太保守了。换了个参数,问题解决。嗯,这种坑,没经验真想不到。
PHY层有几个关键参数你得知道:
- 速率协商:自动协商(Auto-Negotiation)是PHY层的核心功能。两端网卡协商出共同支持的最高速率。我建议你永远不要关闭自动协商,除非你明确知道自己在做什么。强制设置速率经常导致协商失败,链路时断时续。
- MDI/MDIX:自动翻转线序。现在的PHY基本都支持,但老设备上可能是个坑。
- EEE (Energy Efficient Ethernet):节能以太网。省电,但会引入额外的延迟。服务器场景下我一般建议关掉。
ethtool eth0 的输出。重点关注 Speed、Duplex、Link 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 对齐 | 数据在内存中的对齐方式 | 不对齐会导致性能下降,驱动一般会处理好 |
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
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
2.8 总结:一张表记住核心组件
| 组件 | 位置 | 核心功能 | 调优关注点 |
|---|---|---|---|
| PHY | 物理层 | 信号编码/解码、速率协商 | 自动协商、EEE开关 |
| MAC | 数据链路层 | 帧封装/过滤、流量控制 | Pause帧、校验和卸载 |
| DMA | 总线接口 | 数据搬运、内存访问 | 通道数、缓冲区大小 |
| Ring Buffer | 驱动层 | 数据包中转、描述符管理 | 大小设置、溢出监控 |
| 多队列 | 网卡内部 | 并行处理、负载均衡 | 队列数、CPU亲和性 |
| 硬件卸载 | 网卡功能 | TSO/GRO/RSS等 | 按需开启/关闭 |
好了,网卡的硬件架构就聊到这儿。搞懂了这些底层组件,你再去调优,心里就有谱了。下一节咱们会深入Ring Buffer的监控和调优实战,到时候我会手把手教你用工具定位问题。