网卡的 Ring Buffer 详解

1. 网卡处理数据包流程

网卡处理网络数据流程图:

图片来自参考链接1

上图中虚线步骤的解释:

  1. DMA 将 NIC 接收的数据包逐个写入 sk_buff ,一个数据包可能占用多个 sk_buff , sk_buff 读写顺序遵循FIFO(先入先出)原则。
  2. DMA 读完数据之后,NIC 会通过 NIC Interrupt Handler 触发 IRQ (中断请求)。
  3. NIC driver 注册 poll 函数。
  4. poll 函数对数据进行检查,例如将几个 sk_buff 合并,因为可能同一个数据可能被分散放在多个 sk_buff 中。
  5. poll 函数将 sk_buff 交付上层网络栈处理。

完整流程:

  1. 系统启动时 NIC (network interface card)  进行初始化,系统分配内存空间给 Ring Buffer 。
  2. 初始状态下,Ring Buffer 队列每个槽中存放的 Packet Descriptor 指向 sk_buff ,状态均为 ready。
  3. DMA 将 NIC 接收的数据包逐个写入 sk_buff ,一个数据包可能占用多个 sk_buff ,sk_buff 读写顺序遵循FIFO(先入先出)原则。
  4. 被写入数据的 sk_buff 变为 used 状态。
  5. DMA 读完数据之后,NIC 会通过 NIC Interrupt Handler 触发 IRQ (中断请求)。
  6. NIC driver 注册 poll 函数。
  7. poll 函数对数据进行检查,例如将几个 sk_buff 合并,因为可能同一个数据可能被分散放在多个 sk_buff 中。
  8. poll 函数将 sk_buff 交付上层网络栈处理。
  9. poll 函数清理 sk_buff,清理 Ring Buffer 上的 Descriptor 将其指向新分配的 sk_buff 并将状态设置为 ready。

2. 多 CPU 下的 Ring Buffer 处理

因为分配给 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 之外,不会影响别的逻辑了。数据处理过程跟之前描述的是一样的。

3. Ring Buffer 相关命令

在生产实践中,因 Ring Buffer 写满导致丢包的情况很多。当环境中的业务流量过大且出现网卡丢包的时候,考虑到 Ring Buffer 写满是一个很好的思路。

总结下 Ring Buffer 相关的命令:

3.1 网卡收到的数据包统计

[root@server-20.140.beishu.polex.io ~ ]$ ethtool -S em1 | more
NIC statistics:rx_packets: 35874336743tx_packets: 35163830212rx_bytes: 6337524253985tx_bytes: 3686383656436rx_broadcast: 15392577tx_broadcast: 873436rx_multicast: 45849160tx_multicast: 1784024

RX 就是收到数据,TX 是发出数据。

3.2 带有 drop 字样的统计和 fifo_errors 的统计

[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 的大小。

3.3 查询 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 。队列越大丢包的可能越小,但数据延迟会增加。

3.4 调整 Ring Buffer 队列数量

[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 的设置操作可能都要重启一下才能生效。

3.4 调整 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。队列越大丢包的可能越小,但数据延迟会增加.

设置 RX 和 TX 队列大小:

ethtool -G em1 rx 4096
ethtool -G em1 tx 4096

3.5 调整 Ring Buffer 队列的权重

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     08:      0     0     0     0     0     0     0     016:      1     1     1     1     1     1     1     124:      1     1     1     1     1     1     1     132:      2     2     2     2     2     2     2     240:      2     2     2     2     2     2     2     248:      3     3     3     3     3     3     3     356:      3     3     3     3     3     3     3     364:      4     4     4     4     4     4     4     472:      4     4     4     4     4     4     4     480:      5     5     5     5     5     5     5     588:      5     5     5     5     5     5     5     596:      6     6     6     6     6     6     6     6104:      6     6     6     6     6     6     6     6112:      7     7     7     7     7     7     7     7120:      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 可能不一样。

3.6 更改 Ring Buffer Hash Field

分配数据包的时候是按照数据包内的某个字段来进行的,这个字段能进行调整。

[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 看其含义,还有很多别的配置值。

3.6 IRQ 统计

/proc/interrupts 能看到每个 CPU 的 IRQ 统计。一般就是看看 NIC 有没有支持 multiqueue 以及 NAPI 的 IRQ 合并机制是否生效。看看 IRQ 是不是增长的很快。

参考链接:

https://ylgrgyq.github.io/2017/07/23/linux-receive-packet-1/

posted @ 2019-03-10 21:12 MauriceWei 阅读(...) 评论(...) 编辑 收藏

网卡的 Ring Buffer 详解相关推荐

  1. php获取网卡mac地址吗,php获取网卡MAC地址步骤详解

    这次给大家带来php获取网卡MAC地址步骤详解,php获取网卡MAC地址的注意事项有哪些,下面就是实战案例,一起来看一下. php获取网卡的物理地址,即mac地址.<?php /** 获取网卡的 ...

  2. 前端后台以及游戏中使用Google Protocol Buffer详解

    前端后台以及游戏中使用Google Protocol Buffer详解 前端后台以及游戏中使用Google Protocol Buffer详解 0.什么是protoBuf 1.下载protobuf的编 ...

  3. Potocol Buffer详解

    protocol安装及使用 上一篇博文介绍了一个综合案例,这篇将详细介绍protocol buffer. 为什么使用protocol buffer? java默认序列化效率较低. apache的thr ...

  4. linux更换网卡不识别_详解Linux双网卡绑定脚本的方法示例

    概述 linux运维及配置工作中,常常会用到双网卡绑定,少数几台服务器的配置还好,如果是需要配置几十甚至上百台,难免会枯燥乏味,易于出错,我编写了这个双网卡绑定的辅助脚本,可傻瓜式地完成linux双网 ...

  5. NIO详解(五):Buffer详解

    1. 概述 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到通道中的.缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存.这块内存被包 ...

  6. Java NIO学习篇之缓冲区Buffer详解

    定义 缓冲区Buffer在java nio中负责数据的存储,缓冲区就是数组,用于存储不同类型数据的数组. jdk为java七大基本类型数据都准备了响应的缓冲区(boolean值除外): ByteBuf ...

  7. ethtool 开启网卡_Linux 网卡特性配置ethtool详解

    近期遇到一个自定义报文传输性能问题,解决过程中借助了ethtool这个工具,因此发掘一下与此工具相关的网卡的一些特性. ethtool 常用命令如下,比如对eth0的操作: ethtool eth0 ...

  8. linux系统重启网卡的方法步骤详解

    在实际工作中,经常会遇到Linux系统进行重启网卡的操作.接下来是小编为大家收集的linux系统重启网卡方法,希望能帮到大家. linux系统重启网卡方法 一.service network rest ...

  9. linux怎样重启网卡,linux系统重启网卡的方法步骤详解

    在实际工作中,经常会遇到Linux系统进行重启网卡的操作.接下来是小编为大家收集的linux系统重启网卡方法,希望能帮到大家. linux系统重启网卡方法 一.service network rest ...

最新文章

  1. VS可视化调试学习总结
  2. TListBox的项目个数
  3. 分布式一致性协议Raft原理与实例
  4. 中国有超级计算机的大学,计算机专业排名看超算实力,ASC竞赛五大高校排名,中山大学第一...
  5. linux php7 mongodb,CentOS 7下安装配置PHP7跟LAMP及MongoDB和Redis
  6. MYSQL--三种锁
  7. webstorm两个文件比对_webstorm怎么更改文件名称?或者是重命名
  8. js数字比较【牢记】
  9. 平均分配,移动欠费催收款数据的分配应用实例
  10. Google I/O 2016到底讲了啥
  11. Day01_硬盘基本知识
  12. 外卖返利微信小程序源码
  13. 【测试】11月11日的测试
  14. 【加拿大留学】蒙特利尔中国公派学者 学生学习生活指南【蒙特利尔留学必看,第一次出国必看】
  15. 学校机房的网屏蔽了某些网站无法访问怎么办?
  16. 什么是死锁,如何避免死锁?
  17. createjs打飞机
  18. 【剑指Offer】个人学习笔记_46_把数字翻译成字符串
  19. 浅谈Redis面试热点之工程架构篇[1]
  20. 报数游戏(3)--【英雄会】

热门文章

  1. [日更-2019.4.26、27、28] cm-14.1 Android系统启动过程分析(四)-应用程序进程启动过程...
  2. (3年工作经验)天天下班刷抖音,不如亲自跑去抖音瞧一瞧!
  3. Codeforces Round #700 (Div. 2)全部题解
  4. Intel无线网卡蓝牙功能失效解决思路分享
  5. 纱织小姐雅典娜_用雅典娜分析巧克力
  6. OpenCV_contrib配置教程(详细版)
  7. 文件损坏怎么修复回来?
  8. 数据治理系列(三):主数据管理
  9. 实验室预约管理系统(Java+SSH+Web+MySQL+ofbiz系统)
  10. 重要极限一:x趋近于0,sinx/x的极限