网卡处理网络数据流程图:linux
图片来自参考连接1git
上图中虚线步骤的解释:github
完整流程:缓存
由于分配给 Ring Buffer 的空间是有限的,当收到的数据包速率大于单个 CPU 处理速度的时候 Ring Buffer 可能被占满,占满以后再来的新数据包会被自动丢弃。服务器
若是在多核 CPU 的服务器上,网卡内部会有多个 Ring Buffer,NIC 负责将传进来的数据分配给不一样的 Ring Buffer,同时触发的 IRQ 也能够分配到多个 CPU 上,这样存在多个 Ring Buffer 的状况下 Ring Buffer 缓存的数据也同时被多个 CPU 处理,就能提升数据的并行处理能力。网络
固然,要实现“NIC 负责将传进来的数据分配给不一样的 Ring Buffer”,NIC 网卡必须支持 Receive Side Scaling(RSS) 或者叫作 multiqueue 的功能。RSS 除了会影响到 NIC 将 IRQ 发到哪一个 CPU 以外,不会影响别的逻辑了。数据处理过程跟以前描述的是同样的。tcp
在生产实践中,因 Ring Buffer 写满致使丢包的状况不少。当环境中的业务流量过大且出现网卡丢包的时候,考虑到 Ring Buffer 写尽是一个很好的思路。ide
总结下 Ring Buffer 相关的命令:函数
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -S em1 | more NIC statistics: rx_packets: 35874336743 tx_packets: 35163830212 rx_bytes: 6337524253985 tx_bytes: 3686383656436 rx_broadcast: 15392577 tx_broadcast: 873436 rx_multicast: 45849160 tx_multicast: 1784024
RX 就是收到数据,TX 是发出数据。spa
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -S em1 | grep -iE "error|drop"
rx_crc_errors: 0
rx_missed_errors: 0
tx_aborted_errors: 0
tx_carrier_errors: 0
tx_window_errors: 0
rx_long_length_errors: 0
rx_short_length_errors: 0
rx_align_errors: 0
dropped_smbus: 0
rx_errors: 0
tx_errors: 0
tx_dropped: 0
rx_length_errors: 0
rx_over_errors: 0
rx_frame_errors: 0
rx_fifo_errors: 79270
tx_fifo_errors: 0
tx_heartbeat_errors: 0
rx_queue_0_drops: 16669
rx_queue_1_drops: 21522
rx_queue_2_drops: 0
rx_queue_3_drops: 5678
rx_queue_4_drops: 5730
rx_queue_5_drops: 14011
rx_queue_6_drops: 15240
rx_queue_7_drops: 420
发送队列和接收队列 drop 的数据包数量显示在这里。而且全部 queue_drops 加起来等于 rx_fifo_errors。因此整体上能经过 rx_fifo_errors 看到 Ring Buffer 上是否有丢包。若是有的话一方面是看是否须要调整一下每一个队列数据的分配,或者是否要加大 Ring Buffer 的大小。
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -g em1
Ring parameters for em1:
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
RX 和 TX 最大是 4096,当前值为 256 。队列越大丢包的可能越小,但数据延迟会增长。
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -l em1 Channel parameters for em1: Pre-set maximums: RX: 0 TX: 0 Other: 1 Combined: 8 Current hardware settings: RX: 0 TX: 0 Other: 1 Combined: 8
Combined = 8,说明当前 NIC 网卡会使用 8 个进程处理网络数据。
更改 eth0 网卡 Combined 的值:
ethtool -L eth0 combined 8
须要注意的是,ethtool 的设置操做可能都要重启一下才能生效。
查看当前 Ring Buffer 大小:
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -g em1 Ring parameters for em1: 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
看到 RX 和 TX 最大是 4096,当前值为 256。队列越大丢包的可能越小,但数据延迟会增长.
设置 RX 和 TX 队列大小:
ethtool -G em1 rx 4096 ethtool -G em1 tx 4096
NIC 若是支持 mutiqueue 的话 NIC 会根据一个 Hash 函数对收到的数据包进行分发。能调整不一样队列的权重,用于分配数据。
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -x em1 RX flow hash indirection table for em1 with 8 RX ring(s): 0: 0 0 0 0 0 0 0 0 8: 0 0 0 0 0 0 0 0 16: 1 1 1 1 1 1 1 1 24: 1 1 1 1 1 1 1 1 32: 2 2 2 2 2 2 2 2 40: 2 2 2 2 2 2 2 2 48: 3 3 3 3 3 3 3 3 56: 3 3 3 3 3 3 3 3 64: 4 4 4 4 4 4 4 4 72: 4 4 4 4 4 4 4 4 80: 5 5 5 5 5 5 5 5 88: 5 5 5 5 5 5 5 5 96: 6 6 6 6 6 6 6 6 104: 6 6 6 6 6 6 6 6 112: 7 7 7 7 7 7 7 7 120: 7 7 7 7 7 7 7 7 RSS hash key: Operation not supported
个人 NIC 一共有 8 个队列,一共有 128 个不一样的 Hash 值,上面就是列出了每一个 Hash 值对应的队列是什么。最左侧 0 8 16 是为了能让你快速的找到某个具体的 Hash 值。好比 Hash 值是 76 的话咱们能当即找到 72 那一行:”72: 4 4 4 4 4 4 4 4”,从左到右第一个是 72 数第 5 个就是 76 这个 Hash 值对应的队列是 4 。
设置 8 个队列的权重。加起来不能超过 128 。128 是 indirection table 大小,每一个 NIC 可能不同。
分配数据包的时候是按照数据包内的某个字段来进行的,这个字段能进行调整。
[root@server-20.140.beishu.polex.io ~ ]$ ethtool -n em1 rx-flow-hash tcp4 TCP over IPV4 flows use these fields for computing Hash flow key: IP SA IP DA L4 bytes 0 & 1 [TCP/UDP src port] L4 bytes 2 & 3 [TCP/UDP dst port]
也能够设置 Hash 字段:查看 tcp4 的 Hash 字段。
ethtool -N em1 rx-flow-hash udp4 sdfn
sdfn 须要查看 ethtool 看其含义,还有不少别的配置值。
/proc/interrupts
能看到每一个 CPU 的 IRQ 统计。通常就是看看 NIC 有没有支持 multiqueue 以及 NAPI 的 IRQ 合并机制是否生效。看看 IRQ 是否是增加的很快。
参考连接:
https://ylgrgyq.github.io/2017/07/23/linux-receive-packet-1/