这一系列的目标是为了让我们的监控更全面,帮助我们优化和发现潜在问题。它涉及到很多方面,比如连接池的优化,系统层面的监控优化,网络方面,应用本身的监控。我们将先从网络这层去体系化的做这件事情。
关注网络整个流程,最终目的是为了知道哪些地方会造成性能问题,哪些地方会造成数据丢失,以及如何通过工具或者监控指标来发现这些异常。帮助发现隐藏网络问题以及提升故障排查以及运维效率。
本文将整理整体的流程框架,详细介绍网卡和驱动的细节以及围绕网卡和驱动采取的监控手段(图片来自网络)。
(在整理的整个过程中,我也不断在想这些指标的意义,是否确实对我们有意义。但我们不仅仅应该从监控的角度去考虑,我们也要考虑当问题发生时,能否清晰流程,让我们知道到底在哪层出现问题。所以在整理过程中,将围绕vip集群迁移延时问题,去思考底层需要知道些什么,能帮助去排查这种不了了之的问题。)
接受网络数据包与发送网络数据包是一个复杂的过程,涉及到庞杂的底层技术细节。
从应用编程的角度看:
NIC
(网卡)->内核->user space
从网络协议的角度看:
物理层->链路层->ip
->tcp
->应用层
很难将我们熟悉的概念合在一起去讨论这个问题,比如内核中的网络驱动,你最多只能说它工作在数据链路层而不能说它实现了数据链路层。
http://bbs.chinaunix.net/thread-1924872-1-1.html
所以在描述整个过程,将用程序流程的角度去描述。
先梳理接受数据包的过程,大概分为以下几步:
1. 网卡(NIC)收到数据包。
2. 将数据包从网卡硬件缓存转移到内核管理的内存sk_buf中。
3. 硬中断通知内核处理。
4. 内核网卡驱动将sk_buf交给内核协议栈处理。
5. 经过TCP/IP协议栈逐层处理。
6. 应用程序通过read()从socket buffer读取数据。
图一:
image.png
下面我们具体看下各个流程,
步骤1.关于网卡网络故障方面的问题
这个交给网络工程师。如果你对此感兴趣,可参考 https://www.cnblogs.com/Security-Darren/p/4700387.html
步骤2.将数据包从网卡硬件缓存转移到内核管理的内存
网卡接收到数据包之后,首先需要将数据发送到内核中,这中间的桥梁是rx ring buffer
。它是由NIC
和驱动程序共享的一片区域。事实上,rx ring buffer
存储的并不是实际的packet
数据,而是一个描述符,这个描述符指向了它真正的存储地址,具体流程如下:
1). 系统启动NIC
驱动首先在内存中分配一片缓冲区来接收数据包,叫做sk_buffer
。
2). 将上述缓冲区的地址和大小(即文件描述符),加入到rx ring buffer
。
3). 驱动通知网卡有一个新的描述符。
4). 网卡从rx ring buffer
中取出描述符,从而获知缓冲区的地址和大小。
5). 网卡收到新的数据包。
6). 网卡将新数据包通过DMA
直接写到sk_buffer
中:
经过以上的过程,NIC
接受的数据就转移到内核管理的内存sk_buf
中。
当驱动处理速度跟不上网卡收包速度时,驱动来不及分配缓冲区,NIC
接收到的数据包无法及时写到sk_buffer
,就会产生堆积,当NIC
内部缓冲区写满后,就会丢弃部分数据,引起丢包。这部分丢包为rx_fifo_errors
,在/proc/net/dev
中体现为fifo
字段增长,在ifconfig
中体现为overruns
指标增长,ethtool -S em1
中体现为rx_fifo_errors
。
通过ethtool -S em1
来查看这个错误(em1为物理网卡,逻辑网卡无效):
可以看出这里面的err
很多。其中TX表示的是发送数据,RX表示的是接受数据。这个命令可以帮助我们更详细的去定位错误,但一般监控通过/proc/net/dev
关注 drop
和fifo
即可。实际落地过程中,我们需要区分物理网卡,虚拟网卡,docker网络去确定时间监控目标。
如果我们确实要调优,一方面是看是否需要调整一下每个队列数据的分配,或者是否要加大Ring Buffer
的大小。由于修改以上参数需要重启才能有意义,我们对这个参数主要是监控,以方便我们排查错误。
调整 Ring Buffer
队列数量
[root@ ~ ]$ 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
队列大小,查看当前 Ring Buffer
大小
[root@ ~ ]$ 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
步骤4.内核网卡驱动将sk_buf
交给内核协议栈处理
当NIC把数据包通过DMA复制到内核缓冲区sk_buffer
后,NIC
立即发起一个硬件中断。CPU
接收后,首先进入上半部分,网卡中断对应的中断处理程序是网卡驱动程序的一部分,之后由它发起软中断,进入下半部分,开始消费sk_buffer
中的数据,交给内核协议栈处理。
当内核开始消费sk_buffer
中的数据,交由协议栈(如IP
、TCP
)处理之前存在一个缓冲队列。每个CPU
核都有一个backlog
队列,当接收包的速率大于内核协议栈处理的速率时,CPU
的backlog
队列不断增长。当达到设定的netdev_max_backlog
值时,数据包将被丢弃。这主要是由于中断处理的速度低于sk_buffer
增长的速度。这部分丢包可以在cat /proc/net/softnet_stat
的输出结果中进行确认。
待补CPU中断亲缘关系、调优以及监控。。。
网友评论