深入理解Linux网络总结
1、内核如何接收网络包
1.1 RingBuffer到底是什么,RingBuffer为什么会丢包?
问:RingBuffer到底存在那一块,是如何被使用到的,真的就只是一个环形队列吗?RingBuffer内存是预先分配好的,还是随着网络包的收发动态分配?为什么RingBuffer会丢包,如果丢包了应该怎么去解决?
答:
- RingBuffer是内存中的一块特殊区域,RingBuffer包含内核使用的igb_rx_buffer数组和网卡使用的e1000_adv_rx_desc数组,这两个数组存放指向skb的指针,数组的内存是预先分配的,skb是根据收包数据动态申请的。
- RingBuffer有大小和长度限制,长度可以通过ethtool工具查看。如执行"ethtool -g eth0";Pre-set maximums指的是RingBuffer的最大值,Current hardware setting指的是当前的设置。如果内核处理的不及时导致RingBuffer满了,那后面新来的数据包就会被丢弃,通过ethtool和ifconfig工具可以查看是否有RingBuffer溢出发生,可使用"ethtool -S eth0",如果rx_fifo_errors不为0(在ifconfig中体现为overruns指标增长)就表示有包因为RingBuffer装不下而被丢弃了。
- 可以通过"ethtool -G eth1 rx 4096 tx 4096"增大RingBuffer,但是这种方法只能解决偶发的瞬时的丢包,而且会在包排队过多时导致延时增大,正确的做法应该是让内核处理网络包的速度更快一些,
1.2 网络相关的硬中断、软中断都是什么?
问:硬中断和软中断的区别是什么,二者是怎么协作的?为什么操作硬中断号和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等函数中处理。
1.3 Linux里的ksoftirqd内核线程是干什么的?
这几个内核线程是做什么用的?机器上会有几个?为什么有这么多?它们和软中断又是什么关系?
设备有几个核就会有几个ksoftirqd线程,内核线程koftirqd包含了所有软中断的类型,执行不同的处理函数。对于软中断NET_RX_SOFTIRQ。软中断的信息可以从/proc/softirqs读取。
1.4 为什么网卡开启多队列能提升网络性能?
多队列提升网络性能的优化方案的基本原理是什么?什么时候该动用这个方法,用的话开到几个队列合适?
通过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就行了。
1.5 tcpdump是如何工作的?
tcpdump工作在设备层,是通过虚拟协议的方式工作的。它通过调用packet_create将抓包函数以协议的形式挂到ptype_all上。
1.6 iptable/netfilter是在哪一层实现的?
netfilter主要是在IP、ARP等层实现的。可以通过搜索NF_HOOK函数的引用来深入了解其实现。如果配置过于复杂的规则,会消耗过多的CPU,加大网络延迟。
1.7 tcpdump能否抓到被iptable封禁的包?
tcpdump可以抓到iptable封禁的收包,但是抓不到iptable封禁的发包。
1.8 网络接收过程中的CPU开销如何查看?
在网络接收过程中,CPU是如何被消耗的?CPU中的si、sy开销究竟是什么含义?
在网络包的接收处理过程中,主要工作集中在硬中断核软中断上,二者的消耗可以通过top命令来查看。
其中hi是CPU处理硬中断的开销,si是处理软中断的开销,都是以百分比的形式来展示。
如果发现某个核的si过高,那么可能是当前数据包的接收已经非常频繁了,需要通过上面的多队列配置让其它核参与进来。
2、内核是如何与用户进程协作的
2.1 阻塞到底是怎么一回事?
阻塞就是进程因为等待某个事件而主动让出CPU挂起的操作。评估是否阻塞,关键要看进程是否让出CPU。
2.2 同步阻塞IO都需要哪些开销?
从CPU开销角度来看,一次同步阻塞网络IO将导致两次进程上下文切换开销。每一次大约花费3~5微秒。
2.3 多路复用epoll为什么就能提高网络性能?
其它epoll高性能最根本的原因是极大程度地减少无用的进程上下文切换,让进程更专注地处理网络请求。至于红黑树只是提高了epoll查找、添加、删除的效率。
2.4 epoll也是阻塞的?
阻塞不会导致低性能,过多过频繁的阻塞才会。epoll的阻塞和它的高性能并不冲突。
3、内核是如何发送网络包的
3.1在查看内核发送数据消耗的CPU时,应该看sy还是si?
在网络包的发送过程中,用户进程(在内核态)完成了绝大部分的工作,甚至连调用驱动的工作都干了。只有当内核态进程被切走前才会发起软中断。发送过程中,绝大部分(90%)以上的开销都是在用户进程内核态消耗掉了。只有一少部分情况才会触发软中断(NET_TX类型),由软中断ksoftirqd内核线程来发送。所以在监控网络IO对服务器造成的CPU的开销时候,不能仅看si,而是应该把si、sy都考虑进来。
3.2 在服务器上查看/proc/softirqs,为什么NET_RX要比NET_TX大得多?
- 当数据发送完之后,通过硬中断的方式通知驱动发送完毕。但是硬中断无论是有数据接收还是发送完毕,触发的软中断都是NET_RX_SOFTIRQ。
- 对于读来说都要经过NET_RX软中断,都走ksoftirqd线程。对于发送来说,绝大部分工作都在用户进程内核态处理了,只有系统态配额用尽了才会发出NET_TX。
3.3 发送网络数据的时候都涉及哪些内存拷贝操作?
- 第一次拷贝操作是在内核申请完skb之后,这时候会将用户传递进来的buffer里面的数据拷贝到skb,如果要发送的数据量比较大,这个拷贝操作的开销还是不小的(CPU拷贝)。
- 第二拷贝操作是从传输层进入网络层的时候,每一个skb都会被克隆出来一个新的副本。目的是保存原始的skb,当没有收到对方返回ACK时,还可以重新发送,以实现TCP要求的可靠传输。不过这次是浅拷贝,仅拷贝skb描述符本身,所指向的数据还是复用的。
- 第三次拷贝不是必需的,只有当IP层发现skb大于MTU时才需要进行。此时会再申请额外的skb,并将原来的skb拷贝为多个小的skb。
3.4 零拷贝到底是怎么回事?
零拷贝是指数据不用拷贝到用户内存,可以节省两次CPU内存拷贝。
3.5为什么Kafka的网络性能很突出?
使用了零拷贝技术。
4、深度理解本机网络IO
4.1 127.0.0.1本机网络IO需要经过网卡吗?
不需要经过网卡。
4.2 数据包在内核中是什么走向,和外网发送相比流程上有什么差别?
本机网络IO和跨机网络IO比较起来,确实是节约了驱动上的一些开销。发送数据不需要近Ringbuffer的驱动队列,直接把skb传给接收协议栈(经过软中断)。
4.3 访问本机服务时,使用127.0.0.1能比使用本机IP(例如192.168.x.x)更快吗?
没有区别,都会走环回设备lo。
5、深度理解TCP连接建立过程
5.1 为什么服务端程序都需要先listen一下?
内核在响应listen调用的时候是创建了半连接、全连接两个队列,这两个队列是三次握手中很重要的数据结构,有了它们才能正常响应客户端的三次握手。
5.2 半连接队列和全连接队列长度如何确定?
服务端在执行listen的时候就确定好了半连接和全连接队列的长度。
对于半连接队列来说,其最大长度是min(backlog,somaxconn,tcp_max_syn_backlog)+1再向上取整到2dN次幂,但最小不能小于16。如果考虑要加大半连接队列,那么需要一并考虑backlog,somaxconn,tcp_max_syn_backlog。
对于全连接队列来说,其最大长度是listen时传入的backlog和net.core.somaxconn之间较小的那个值。如果需要加大全连接队列,那么调整backlog和somaxconn。
5.3 "Cannot assign requested address"这个报错你知道是怎么回事吗?该如何解决?
一条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状态连接数量等方法都是可行的。
5.4 一个客户端端口可以同时用在两条连接上吗?
可以。
5.5 服务端半/全连接队列满了会怎么样?
服务端响应的第一次握手的时候,会进行半连接队列和全连接队列满的判断。如果半连接队列满了,且未开启tcp_syncookies,那么该握手包将直接被丢弃,所以建议不要关闭这个内核参数。如果全连接队列满了,且有young_ack(表示刚刚有ACK到达),那么同样也是直接丢弃。
5.6 新连接的socket内核对象是什么时候建立的?
在第三次握手完成时就创建好了。
5.7 建立一条TCP连接需要消耗多长时间?
正常情况是1个RTT时间。如果丢包就至少1秒了。
5.8 把服务器部署在北京,给纽约的用户访问可行吗?
可以,但是服务延迟太高,最好在当地建立服务器。
5.9服务器负载很正常,但是CPU被打到底是怎么回事?
在端口极其不充足的情况下,connect系统调用的内部循环需要全部执行完毕才能判断出来没有端口可用。如果发出的连接特别频繁就会消耗掉大量的CPU。
相关文章:

深入理解Linux网络总结
1、内核如何接收网络包 1.1 RingBuffer到底是什么,RingBuffer为什么会丢包? 问:RingBuffer到底存在那一块,是如何被使用到的,真的就只是一个环形队列吗?RingBuffer内存是预先分配好的,还是随着…...

Python冷知识
Python作为一种广泛使用的编程语言,有许多功能和特性可能不为初学者或普通用户所熟知。以下是一些相对冷门但有趣的Python知识: 魔术方法:Python中有一些特殊的方法,通常以双下划线__开头和结尾,被称为魔术方法(或特殊方法)。例如,__init__用于初始化对象,__str__返回…...

Redis之内存管理过期、淘汰机制
1.Redis内存管理 我们的redis是一个内存型数据库,我们的数据也都是放在内存中的,内存是有限的空间,当数据满了之后,我们要怎么样继续保证redis的可用性呢?我们就需要采取点管理措施和机制来保证我们redis的可用性。 在redis.co…...

金融科技赋能跨境支付:便捷与安全并驾齐驱
一、引言 在全球经济一体化的背景下,跨境支付作为国际贸易和金融活动的重要组成部分,正迎来金融科技浪潮的洗礼。金融科技以其独特的创新性和颠覆性,正在重塑跨境支付市场的格局,使其更加便捷、高效且安全。本文旨在探讨金融科技如何助力跨境支付,实现便捷与安全并存,并…...

【康耐视国产案例】智能AI相机:深度解析DataMan 380大视野高速AI读码硬实力
随着读码器技术的不断更新迭代,大视野高速应用成为当前工业读码领域的关键发展方向。客户对大视野高速读码器的需求源于其能显著减少生产成本并提升工作效率。然而,大视野应用场景往往伴随着对多个条码的读取需求,这无疑增加了算法的处理负担…...

SQL实验 带函数查询和综合查询
一、实验目的 1.掌握Management Studio的使用。 2.掌握带函数查询和综合查询的使用。 二、实验内容及要求 1.统计年龄大于30岁的学生的人数。 --统计年龄大于30岁的学生的人数。SELECT COUNT(*) AS 人数FROM StudentWHERE (datepart(yea…...

【前端每日基础】day34——HTTP和HTTPS
HTTP(Hypertext Transfer Protocol)和HTTPS(Hypertext Transfer Protocol Secure)是互联网通信协议,用于在Web浏览器和Web服务器之间传输数据。以下是对HTTP和HTTPS的详细介绍: HTTP(Hypertext…...

go mongo 唯一索引创建
1. 登录mongo,创建数据库 mongosh -u $username -p $password use test 2. 查看集合索引 db.$collection_name.getIndexes() 为不存在的集合创建字段唯一索引 package mainimport ("context""fmt""log""time""go…...

微信小程序如何进行页面跳转
微信小程序中的页面跳转可以通过多种方式实现,以下是几种主要的跳转方式及其详细解释: wx.navigateTo 功能:保留当前页面,跳转到应用内的某个页面。特点: 可以在新页面使用wx.navigateBack返回原页面。每跳转一个新页…...

信息标记形式 (XML, JSON, YAML)
文章目录 🖥️介绍🖥️三种形式🏷️XML (Extensible Markup Language)🔖规范🔖注释🔖举例🔖其他 🏷️JSON (JavaScript Object Notation)🔖规范🔖注释&#x…...

C语言:学生成绩管理系统(含源代码)
一.功能 二.源代码 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_NUM 100 typedef struct {char no[30];char name[10];char sex[10];char phone[20];float cyuyan;float computer;float datastruct; } *student, student1;typ…...

MySQL 导出导入的101个坑
最近接到一个业务自行运维的MySQL库迁移至标准化环境的需求,库不大,迁移方式也很简单,由开发用myqldump导出数据、DBA导入,但迁移过程坎坷十足,记录一下遇到的各项报错及后续迁移注意事项。 一、 概要 空间问题源与目…...

OpenCv之简单的人脸识别项目(人脸提取页面)
人脸识别 准备五、人脸提取页面1.导入所需的包2.设置窗口2.1定义窗口外观和大小2.2设置窗口背景2.2.1设置背景图片2.2.2创建label控件 3.定义单人脸提取脚本4.定义多人脸提取脚本5.创建一个退出对话框6.按钮设计6.1单人脸提取按钮6.2多人脸提取按钮6.3返回按钮 7.定义关键函数8…...

linux 内核映像差异介绍:vmlinux、zImage、zbImage、image、uImage等
一、背景 Linux内核是整个Linux操作系统的核心部分,它是一个负责与硬件直接交互的软件层,并且提供多种服务和接口,让用户程序能够方便地使用硬件资源。 当我们编译自定义内核时,可以将其生成为以下内核映像之一:vmli…...

【Linux-INPUT输入的子系统】
Linux-INPUT输入的子系统 ■ input 子系统简介■ input 驱动编写流程■ 事件类型 ■ ■ input 子系统简介 input 子系统就是管理输入的子系统, input 子系统分为 input 驱动层、 input 核心层、 input 事件处理层,最终给用户空间提供可访问的设备节点 …...

密码加密及验证
目录 为什么需要加密? 密码算法分类 对称密码算法 非对称密码算法 摘要算法 DigestUtils MD5在线解密工具原理 实现用户密码加密 代码实现 为什么需要加密? 在MySQL数据库中,我们常常需要对用户密码、身份证号、手机号码等敏感信息进…...

找出字符串中出现最多次数的字符以及出现的次数
str.charAt(i) 是JavaScript中获取字符串中特定位置字符的方法,表示获取当前的字符。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wi…...

如何看待央行买卖长期国债?
央行远比大家想象中的要渴求货币宽松。 引子 今年以来,有不少关于“央行买卖长期国债”的讨论,前些时候关注点在“买”,最近关注点在“卖”。 然而,市场上的讨论采用了十分粗糙和松散的“自然语言”,所以࿰…...

MATLAB算法实战应用案例精讲-【数模应用】Turf组合模型(附MATLAB、python和R语言代码实现)
目录 几个高频面试题目 如何以最小的成本覆盖到最大的消费群体? 应用场景 TURF举例...

android源码下载编译模拟器运行
安卓aosp源码下载,编译,模拟器运行 virtualbox7 安装ubuntu20.04,ubuntu22.04 编译android aosp 源码可以,但是模拟器跑不了,哪个版本都是要么黑屏,要么整个vbox虚拟机闪退。解决方案使用vmware17 ##拯救…...

Golang:Sirupsen/logrus是一个日志库
Sirupsen/logrus是一个日志库 文档 https://github.com/Sirupsen/logrus 安装 go get github.com/sirupsen/logrus代码示例 package mainimport ("github.com/sirupsen/logrus" )func main() {var log logrus.New()log.Trace("Something very low level.&…...

Android Studio插件开发 - Dora SDK的IDE插件
IDE插件开发简介 Android Studio是一种常用的集成开发环境(IDE),用于开发Android应用程序。它提供了许多功能和工具,可以帮助开发人员更轻松地构建和调试Android应用程序。 如果你想开发Android Studio插件,以下是一…...

【mybatis】缓存
一级缓存和二级缓存 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从一级缓存中直接获取,不会从数据库重新查询。一级缓存默认是开启 使一级缓存失效的四种情况: 11.1…...

自定义类型:结构体类型
在学习完指针相关的知识后将进入到c语言中又一大重点——自定义类型,在之前学习操作符以及指针时我们对自定义类型中的结构体类型有了初步的了解,学习了结构体类型的创建以及如何创建结构体变量,还有结构体成员操作符的使用,现在我…...

C++对象移动
在某些情况下,对象拷贝后就立即被销毁了,这时利用新标准(C11)提供的对象移动而非拷贝将大幅提升性能. 1.右值引用 为了支持移动操作,c11新增了一种引用 - 右值引用(rvalue reference)。这种引用必须指向右值,使用&&声明。 右值引用只能引用临时变量或常量值. 右值引用…...

“华为杯”第十三届中国研究生 数学建模竞赛-E题:粮食最低收购价政策问题研究(续)
目录 4.3 问题三:粮食价格的特殊规律性模型 4.3.1 分析和建模 4.3.2 求解和结果...

(一)django目录介绍
1、生成django项目,得到的目录如下 manage.py:命令行工具,内置多种方式与项目进行交互。在命令提示符窗口下,将路径切换到项目并输入python manage.py help,可以查看该工具的指令信息。 默认的数据库工具,sqlite 在…...

leetcode5 最长回文子串
给你一个字符串 s,找到 s 中最长的 回文 子串。 示例 1: 输入:s "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。示例 2: 输入:s "cbbd" 输…...

《论文阅读》通过顺序不敏感的表示正则化实现稳健的个性化对话生成 ACL 2023
《论文阅读》通过顺序不敏感的表示正则化实现稳健的个性化对话生成 ACL 2023 前言 相关个性化生成论文推荐简介问题定义方法损失函数实验结果 前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手…...

python采集汽车价格数据
python采集汽车价格数据 一、项目简介二、完整代码一、项目简介 本次数据采集的目标是车主之家汽车价格数据,采集的流程包括寻找数据接口、发送请求获取响应、解析数据和持久化存储,先来看一下数据情况,完整代码附后: 二、完整代码 #输入请求页面url #返回html文档 imp…...