关于linux:Linux网络包接收过程的监控与调优

56次阅读

共计 7545 个字符,预计需要花费 19 分钟才能阅读完成。

上一篇文章中《图解 Linux 网络包接管过程》,咱们梳理了在 Linux 零碎下一个数据包被接管的整个过程。Linux 内核对网络包的接管过程大抵能够分为接管到 RingBuffer、硬中断解决、ksoftirqd 软中断解决几个过程。其中在 ksoftirqd 软中断解决中,把数据包从 RingBuffer 中摘下来,送到协定栈的解决,再之后送到用户过程 socket 的接管队列中。

了解了 Linux 工作原理之后,还有更重要的两件事件。第一是入手监控,会理论查看网络包接管的整体状况。第二是调优,当你的服务器有问题的时候,你能找到瓶颈所在,并会利用内核凋谢的参数进行调节。

先说几个工具

在正式内容开始之前,咱们先来理解几个 Linux 下监控网卡时可用的工具。

ethtool

首先第一个工具就是咱们在上文中提到的ethtool,它用来查看和设置网卡参数。这个工具其实自身只是提供几个通用接口,真正的实现是都是在网卡驱动中的。正因为该工具是由驱动间接实现的,所以集体感觉它最重要。

该命令比较复杂,咱们选几个明天能用到的说

  • -i 显示网卡驱动的信息,如驱动的名称、版本等
  • -S 查看网卡收发包的统计状况
  • -g/-G 查看或者批改 RingBuffer 的大小
  • -l/-L 查看或者批改网卡队列数
  • -c/-C 查看或者批改硬中断合并策略

理论查看一下网卡驱动:

# ethtool -i eth0
driver: ixgbe
......  

这里看到我的机器上网卡驱动程序是 ixgbe。有了驱动名称,就能够在源码中找到对应的代码了。对于 ixgbe 来说,其驱动的源代码位于 drivers/net/ethernet/intel/ixgbe 目录下。ixgbe_ethtool.c下都是实现的供 ethtool 应用的相干函数,如果 ethtool 哪里有搞不明确的,就能够通过这种形式查找到源码来读。另外咱们前文《图解 Linux 网络包接管过程》里提到的 NAPI 收包时的 poll 回调函数,启动网卡时的 open 函数都是在这里实现的。

ifconfig

网络管理工具 ifconfig 不只是能够为网卡配置 ip,启动或者禁用网卡,也蕴含了一些网卡的统计信息。

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.162.42.51  netmask 255.255.248.0  broadcast 10.162.47.255
        inet6 fe80::6e0b:84ff:fed5:88d1  prefixlen 64  scopeid 0x20<link>
        ether 6c:0b:84:d5:88:d1  txqueuelen 1000  (Ethernet)
        RX packets 2953454  bytes 414212810 (395.0 MiB)
        RX errors 0  dropped 4636605  overruns 0  frame 0
        TX packets 127887  bytes 82943405 (79.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • RX packets:接管的总包数
  • RX bytes:接管的字节数
  • RX errors:示意总的收包的谬误数量
  • RX dropped:数据包曾经进入了 Ring Buffer,然而因为其它起因导致的丢包
  • RX overruns:示意了 fifo 的 overruns,这是因为 Ring Buffer 有余导致的丢包

伪文件系统 /proc

Linux 内核提供了 /proc 伪文件系统,通过 /proc 能够查看内核外部数据结构、扭转内核设置。咱们先跑一下题,看一下这个伪文件系统里都有啥:

  • /proc/sys目录能够查看或批改内核参数
  • /proc/cpuinfo能够查看 CPU 信息
  • /proc/meminfo能够查看内存信息
  • /proc/interrupts统计所有的硬中断
  • /proc/softirqs统计的所有的软中断信息
  • /proc/slabinfo统计了内核数据结构的 slab 内存应用状况
  • /proc/net/dev能够看到一些网卡统计数据

具体聊下伪文件/proc/net/dev,通过它能够看到内核中对网卡的一些相干统计。蕴含了以下信息:

  • bytes: 发送或接管的数据的总字节数
  • packets: 接口发送或接管的数据包总数
  • errs: 由设施驱动程序检测到的发送或接管谬误的总数
  • drop: 设施驱动程序抛弃的数据包总数
  • fifo: FIFO 缓冲区谬误的数量
  • frame: The number of packet framing errors.(分组帧谬误的数量)
  • colls: 接口上检测到的抵触数

所以,伪文件 /proc/net/dev 也能够作为咱们查看网卡工作统计数据的工具之一。

伪文件系统 sysfs

sysfs 和 /proc 相似,也是一个伪文件系统,然而比 proc 更新,构造更清晰。其中的 /sys/class/net/eth0/statistics/ 也蕴含了网卡的统计信息。

# cd /sys/class/net/eth0/statistics/ 
# grep . * | grep tx
tx_aborted_errors:0
tx_bytes:170699510
tx_carrier_errors:0
tx_compressed:0
tx_dropped:0
tx_errors:0
tx_fifo_errors:0
tx_heartbeat_errors:0
tx_packets:262330
tx_window_errors:0

好了,简略理解过这几个工具当前,让咱们正式开始明天的行程。

RingBuffer 监控与调优

后面咱们看到,当网线中的数据帧达到网卡后,第一站就是 RingBuffer(网卡通过 DMA 机制将数据帧送到 RingBuffer 中)。因而咱们第一个要监控和调优的就是网卡的 RingBuffer,咱们应用 ethtool 来来查看一下 Ringbuffer。

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

这里看到我手头的网卡设置 RingBuffer 最大容许设置到 4096,目前的理论设置是 512。

这里有一个小细节,ethtool 查看到的是理论是 Rx bd 的大小。Rx bd 位于网卡中,相当于一个指针。RingBuffer 在内存中,Rx bd 指向 RingBuffer。Rx bd 和 RingBuffer 中的元素是一一对应的关系。在网卡启动的时候,内核会为网卡的 Rx bd 在内存中调配 RingBuffer,并设置好对应关系。

在 Linux 的整个网络栈中,RingBuffer 起到一个工作的收发中转站的角色。对于接管过程来讲,网卡负责往 RingBuffer 中写入收到的数据帧,ksoftirqd 内核线程负责从中取走解决。只有 ksoftirqd 线程工作的足够快,RingBuffer 这个中转站就不会呈现问题。然而咱们构想一下,如果某一时刻,霎时来了特地多的包,而 ksoftirqd 解决不过去了,会产生什么?这时 RingBuffer 可能霎时就被填满了,前面再来的包网卡间接就会抛弃,不做任何解决!

那咱们怎么样能看一下,咱们的服务器上是否有因为这个起因导致的丢包呢?后面咱们介绍的四个工具都能够查看这个丢包统计,拿 ethtool 来举例:

# ethtool -S eth0
......
rx_fifo_errors: 0
tx_fifo_errors: 0

rx_fifo_errors 如果不为 0 的话(在 ifconfig 中体现为 overruns 指标增长),就示意有包因为 RingBuffer 装不下而被抛弃了。那么怎么解决这个问题呢?很天然首先咱们想到的是,加大 RingBuffer 这个“直达仓库”的大小。通过 ethtool 就能够批改。

# ethtool -G eth1 rx 4096 tx 4096

这样网卡会被调配更大一点的”中转站“,能够解决偶发的刹时的丢包。不过这种办法有个小副作用,那就是排队的包过多会减少解决网络包的延时。所以另外一种解决思考更好,。那就是让内核解决网络包的速度更快一些,而不是让网络包傻傻地在 RingBuffer 中排队。怎么放慢内核生产 RingBuffer 中工作的速度呢,别着急,咱们持续往下看 …

硬中断监控与调优

在数据被接管到 RingBuffer 之后,下一个执行就是就是硬中断的发动。咱们先来查看硬中断,而后再聊下怎么优化。

监控

硬中断的状况能够通过内核提供的伪文件 /proc/interrupts 来进行查看。

$ cat  /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
  0:         34          0          0          0   IO-APIC-edge      timer
 ......
 27:        351          0          0 1109986815   PCI-MSI-edge      virtio1-input.0
 28:       2571          0          0          0   PCI-MSI-edge      virtio1-output.0
 29:          0          0          0          0   PCI-MSI-edge      virtio2-config
 30:    4233459 1986139461     244872     474097   PCI-MSI-edge      virtio2-input.0
 31:          3          0          2          0   PCI-MSI-edge      virtio2-output.0

上述后果是我手头的一台虚机的输入后果。下面蕴含了十分丰盛的信息,让咱们一一道来:

  • 网卡的输出队列 virtio1-input.0 的中断号是 27
  • 27 号中断都是由 CPU3 来解决的
  • 总的中断次数是 1109986815。

这里有两个细节咱们须要关注一下。
1)为什么输出队列的中断都在 CPU3 上呢?
这是因为内核的一个配置,在伪文件系统中能够查看到。

#cat /proc/irq/27/smp_affinity
8

smp_affinity里是 CPU 的亲和性的绑定,8 是二进制的 1000, 第 4 位为 1,代表的就是第 4 个 CPU 外围 -CPU3。

2)对于收包来过程来讲,硬中断的总次数示意的是 Linux 收包总数吗?
不是,硬件中断次数不代表总的网络包数。第一网卡能够设置中断合并,多个网络帧能够只发动一次中断。第二 NAPI 运行的时候会敞开硬中断,通过 poll 来收包。

多队列网卡调优

当初的支流网卡基本上都是反对多队列的,咱们能够通过将不同的队列分给不同的 CPU 外围来解决,从而放慢 Linux 内核解决网络包的速度。这是最为有用的一个优化伎俩。

每一个队列都有一个中断号,能够独立向某个 CPU 外围发动硬中断请求,让 CPU 来 poll 包。通过将接管进来的包被放到不同的内存队列里,多个 CPU 就能够同时别离向不同的队列发动生产了。这个个性叫做 RSS(Receive Side Scaling,接收端扩大)。通过 ethtool 工具能够查看网卡的队列状况。

# ethtool -l eth0
Channel parameters for eth0:
Pre-set maximums:
RX:        0
TX:        0
Other:        1
Combined:    63
Current hardware settings:
RX:        0
TX:        0
Other:        1
Combined:    8

上述后果示意以后网卡反对的最大队列数是 63,以后开启的队列数是 8。对于这个配置来讲,最多同时能够有 8 个外围来参加网络收包。如果你想进步内核收包的能力,间接简略加大队列数就能够了,这比加大 RingBuffer 更为有用。因为加大 RingBuffer 只是给个更大的空间让网络帧能持续排队,而加大队列数则能让包更早地被内核解决。ethtool批改队列数量办法如下:

#ethtool -L eth0 combined 32

咱们前文说过,硬中断产生在哪一个核上,它收回的软中断就由哪个核来解决。所有通过加大网卡队列数,这样硬中断工作、软中断工作都会有更多的外围参加进来。

每一个队列都有一个中断号,每一个中断号都是绑定在一个特定的 CPU 上的。如果你不称心某一个中断的 CPU 绑定,能够通过批改 /proc/irq/{中断号}/smp_affinity 来实现。

个别解决到这里,网络包的接管就没有大问题了。但如果你有更高的谋求,或者是说你并没有更多的 CPU 外围能够参加进来了,那怎么办?释怀,咱们也还有办法进步单核的解决网络包的接管速度。

硬中断合并

先来讲一个理论中的例子,如果你是一位开发同学,和你对口的产品经理一天有 10 个小需要须要让你帮忙来解决。她对你有两种中断形式:

  • 第一种:产品经理想到一个需要,就过去找你,和你形容需要细节,而后让你帮你来改
  • 第二种:产品经理想到需要后,不来打搅你,等攒够 5 个来找你一次,你集中处理

咱们当初不思考及时性,只思考你的工作整体效率,你感觉那种计划下你的工作效率会高呢?或者换句话说,你更喜爱哪一种工作状态呢?很显著,只有你是一个失常的开发,都会感觉第二种计划更好。对人脑来讲,频繁的中断会打乱你的打算,你脑子里方才刚想到一半技术计划可能也就废了。当产品经理走了当前,你再想捡起来刚被中断之的工作的时候,很可能得花点工夫回顾一会儿能力持续工作。

对于 CPU 来讲也是一样,CPU 要做一件新的事件之前,要加载该过程的地址空间,load 过程代码,读取过程数据,各级别 cache 要缓缓热身。因而如果能适当升高中断的频率,多攒几个包一起收回中断,对晋升 CPU 的工作效率是有帮忙的。所以,网卡容许咱们对硬中断进行合并。

当初咱们来看一下网卡的硬中断合并配置。

# ethtool -c eth0
Coalesce parameters for eth0:
Adaptive RX: off  TX: off
......

rx-usecs: 1
rx-frames: 0
rx-usecs-irq: 0
rx-frames-irq: 0
......

咱们来说一下上述后果的大抵含意

  • Adaptive RX: 自适应中断合并,网卡驱动本人判断啥时候该合并啥时候不合并
  • rx-usecs:当过这么长时间过后,一个 RX interrupt 就会被产生
  • rx-frames:当累计接管到这么多个帧后,一个 RX interrupt 就会被产生

如果你想好了批改其中的某一个参数了的话,间接应用 ethtool -C 就能够,例如:

ethtool -C eth0 adaptive-rx on

不过须要留神的是,缩小中断数量尽管能使得 Linux 整体吞吐更高,不过一些包的提早也会增大,所以用的时候得适当留神。

软中断监控与调优

在硬中断之后,再接下来的处理过程就是 ksoftirqd 内核线程中解决的软中断了。之前咱们说过,软中断和它对应的硬中断是在同一个外围上解决的。因而,后面硬中断扩散到多核上解决的时候,软中断的优化其实也就跟着做了,也会被多核解决。不过软中断也还有本人的可优化选项。

监控

软中断的信息能够从 /proc/softirqs 读取:

$ cat /proc/softirqs
                    CPU0       CPU1       CPU2       CPU3
          HI:          0          2          2          0
       TIMER:  704301348 1013086839  831487473 2202821058
      NET_TX:      33628      31329      32891     105243
      NET_RX:  418082154 2418421545  429443219 1504510793
       BLOCK:         37          0          0   25728280
BLOCK_IOPOLL:          0          0          0          0
     TASKLET:     271783     273780     276790     341003
       SCHED: 1544746947 1374552718 1287098690 2221303707
     HRTIMER:          0          0          0          0
         RCU: 3200539884 3336543147 3228730912 3584743459

软中断 budget 调整

不晓得你有没有据说过番茄工作法,它的大抵意思就是你要有一整段的不被打搅的工夫,集中精力解决某一项作业。这一整段工夫时长被倡议是 25 分钟。
对于咱们的 Linux 的解决软中断的 ksoftirqd 来说,它也和番茄工作法思路相似。一旦它被硬中断触发开始了工作,它会集中精力解决一波儿网络包(绝不只是 1 个),而后再去做别的事件。

咱们说的解决一波儿是多少呢,策略略简单。咱们只说其中一个比拟容易了解的,那就是 net.core.netdev_budget 内核参数。

#sysctl -a | grep 
net.core.netdev_budget = 300

这个的意思说的是,ksoftirqd 一次最多解决 300 个包,解决够了就会把 CPU 被动让进去,以便 Linux 上其它的工作能够失去解决。那么如果说,咱们当初就是想进步内核解决网络包的效率。那就能够让 ksoftirqd 过程多干一会儿网络包的接管,再让出 CPU。至于怎么进步,间接批改不这个参数的值就好了。

#sysctl -w net.core.netdev_budget=600

如果要保障重启依然失效,须要将这个配置写到 /etc/sysctl.conf

软中断 GRO 合并

GRO 和硬中断合并的思维很相似,不过阶段不同。硬中断合并是在中断发动之前,而 GRO 曾经到了软中断上下文中了。

如果利用中是大文件的传输,大部分包都是一段数据,不必 GRO 的话,会每次都将一个小包传送到协定栈(IP 接管函数、TCP 接管)函数中进行解决。开启 GRO 的话,Linux 就会智能进行包的合并,之后将一个大包传给协定处理函数。这样 CPU 的效率也是就进步了。

ethtool -k eth0 | grep generic-receive-offload
generic-receive-offload: on

如果你的网卡驱动没有关上 GRO 的话,能够通过如下形式关上。

# ethtool -K eth0 gro on  

GRO 说的仅仅只是包的接管阶段的优化形式,对于发送来说是 GSO。

总结

在网络技术这一畛域里,有太多的常识内容都停留在实践阶段了。你可能感觉你的网络学的滚瓜烂熟了,可是当你的线上服务呈现问题的时候,你还是不晓得该怎么排查,怎么优化。这就是因为只懂了实践,而不分明 Linux 是通过哪些内核机制将网络技术落地的,各个内核组件之间怎么配合,每个组件有哪些参数能够做调整。咱们用两篇文章具体探讨了 Linux 网络包的接管过程,以及这个过程中的一些统计数据如何查看,如何调优。置信消化完这两篇文章之后,你的网络的了解间接能晋升 1 个 Level,你对线上服务的把控能力也会更加蛟龙得水。



开发内功修炼之硬盘篇专辑:

  • 图解 Linux 网络包接管过程
  • Linux 网络包接管过程的监控与调优
  • 聊聊 TCP 连贯耗时的那些事儿

我的公众号是「开发内功修炼」,在这里我不是单纯介绍技术实践,也不只介绍实践经验。而是把实践与实际联合起来,用实际加深对实践的了解、用实践进步你的技术实际能力。欢送你来关注我的公众号,也请分享给你的好友~~~

正文完
 0