赞
踩
问:RingBuffer到底存在那一块,是如何被使用到的,真的就只是一个环形队列吗?RingBuffer内存是预先分配好的,还是随着网络包的收发动态分配?为什么RingBuffer会丢包,如果丢包了应该怎么去解决?
答:
问:硬中断和软中断的区别是什么,二者是怎么协作的?为什么操作硬中断号和CPU之间的绑定关系,但最终的效果是软中断跟着一起绑定调整了,软中断开销也被绑定到不同的CPU?
在网卡将数据放到RingBuffer中后,接着就发起硬中断,通知CPU进行处理。不过硬中断的上下文里做的工作很少,将传过来的poll_list添加到CPU变量softnet_data的poll_list里(softnet_data中的poll_list是一个双向列表,其中的设备都带有输入帧等着被处理),接着触发软中断NET_RX_SOFTIRQ。
在软中断中对softnet_data的设备列表poll_list进行遍历,执行网卡驱动提供的poll来收取网络包。处理完后会送到协议栈的ip_rcv、udp_rcv、tcp_rcv_v4等函数中处理。
这几个内核线程是做什么用的?机器上会有几个?为什么有这么多?它们和软中断又是什么关系?
设备有几个核就会有几个ksoftirqd线程,内核线程koftirqd包含了所有软中断的类型,执行不同的处理函数。对于软中断NET_RX_SOFTIRQ。软中断的信息可以从/proc/softirqs读取。
多队列提升网络性能的优化方案的基本原理是什么?什么时候该动用这个方法,用的话开到几个队列合适?
通过ethtool可以查看当前网卡的多队列情况(”ethtool -l eth0“)。使用”ls /sys/class/net/eth0/queues“命令也可以看到真正生效的队列数,如果要加大队列数"ethtool -L eth0 combined 32"调整。通过/proc/interrupts可以看到该队列对应的硬件中断号。通过该中断号对应的smp_affinity可以查看到亲和的CPU和是哪一个"cat /proc/irq/中断号/smp_affinity"。这个亲和性通过比特位来标记。8代表的是第4个CPU核心-CPU3。在硬中断的处理中,发起软中断的时候是基于当前CPU核的smp_processor_id的,这意味着哪个核响应的硬中断,那么该硬中断发起的软中断任务就必然由这个核来处理。
如果网络包的接收频率高而导致个别核si偏高,那么通过加大网卡队列数,并设置每个队列中断号的smp_affinty,将各个队列打散到不同的CPU就行了。
tcpdump工作在设备层,是通过虚拟协议的方式工作的。它通过调用packet_create将抓包函数以协议的形式挂到ptype_all上。
netfilter主要是在IP、ARP等层实现的。可以通过搜索NF_HOOK函数的引用来深入了解其实现。如果配置过于复杂的规则,会消耗过多的CPU,加大网络延迟。
tcpdump可以抓到iptable封禁的收包,但是抓不到iptable封禁的发包。
在网络接收过程中,CPU是如何被消耗的?CPU中的si、sy开销究竟是什么含义?
在网络包的接收处理过程中,主要工作集中在硬中断核软中断上,二者的消耗可以通过top命令来查看。
其中hi是CPU处理硬中断的开销,si是处理软中断的开销,都是以百分比的形式来展示。
如果发现某个核的si过高,那么可能是当前数据包的接收已经非常频繁了,需要通过上面的多队列配置让其它核参与进来。
阻塞就是进程因为等待某个事件而主动让出CPU挂起的操作。评估是否阻塞,关键要看进程是否让出CPU。
从CPU开销角度来看,一次同步阻塞网络IO将导致两次进程上下文切换开销。每一次大约花费3~5微秒。
其它epoll高性能最根本的原因是极大程度地减少无用的进程上下文切换,让进程更专注地处理网络请求。至于红黑树只是提高了epoll查找、添加、删除的效率。
阻塞不会导致低性能,过多过频繁的阻塞才会。epoll的阻塞和它的高性能并不冲突。
在网络包的发送过程中,用户进程(在内核态)完成了绝大部分的工作,甚至连调用驱动的工作都干了。只有当内核态进程被切走前才会发起软中断。发送过程中,绝大部分(90%)以上的开销都是在用户进程内核态消耗掉了。只有一少部分情况才会触发软中断(NET_TX类型),由软中断ksoftirqd内核线程来发送。所以在监控网络IO对服务器造成的CPU的开销时候,不能仅看si,而是应该把si、sy都考虑进来。
零拷贝是指数据不用拷贝到用户内存,可以节省两次CPU内存拷贝。
使用了零拷贝技术。
不需要经过网卡。
本机网络IO和跨机网络IO比较起来,确实是节约了驱动上的一些开销。发送数据不需要近Ringbuffer的驱动队列,直接把skb传给接收协议栈(经过软中断)。
没有区别,都会走环回设备lo。
内核在响应listen调用的时候是创建了半连接、全连接两个队列,这两个队列是三次握手中很重要的数据结构,有了它们才能正常响应客户端的三次握手。
服务端在执行listen的时候就确定好了半连接和全连接队列的长度。
对于半连接队列来说,其最大长度是min(backlog,somaxconn,tcp_max_syn_backlog)+1再向上取整到2dN次幂,但最小不能小于16。如果考虑要加大半连接队列,那么需要一并考虑backlog,somaxconn,tcp_max_syn_backlog。
对于全连接队列来说,其最大长度是listen时传入的backlog和net.core.somaxconn之间较小的那个值。如果需要加大全连接队列,那么调整backlog和somaxconn。
一条TCP连接由一个四元组构成:Server IP、Server PORT、Client IP、Client Port。在连接建立前,前面的三个元素是确定了的,只有Client Port是需要动态选择出来的。
客户端在connect发起的时候自动选择端口号。具体的选择过程就是随机地从ip_local_port_rang选择一个位置开始循环判断,跳过ip_local_reserver_ports里设置的端口,然后挨个判断是否可用。如果循环完也没有找到可用的端口,会报错"Cannot assign requested address"。
解决方法:扩大可用端口范围、减小最大TIME_WAIT状态连接数量等方法都是可行的。
可以。
服务端响应的第一次握手的时候,会进行半连接队列和全连接队列满的判断。如果半连接队列满了,且未开启tcp_syncookies,那么该握手包将直接被丢弃,所以建议不要关闭这个内核参数。如果全连接队列满了,且有young_ack(表示刚刚有ACK到达),那么同样也是直接丢弃。
在第三次握手完成时就创建好了。
正常情况是1个RTT时间。如果丢包就至少1秒了。
可以,但是服务延迟太高,最好在当地建立服务器。
在端口极其不充足的情况下,connect系统调用的内部循环需要全部执行完毕才能判断出来没有端口可用。如果发出的连接特别频繁就会消耗掉大量的CPU。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。