技术标签: linux
当我们用TCP创建一个连接的时候,细心的同学可能会发现使用free命令会看到cache的大小就会变大,相应的剩余内存会变小。这是因为内核为每个连接建立了缓冲区,这个缓冲区既要用于发送和接收数据,还要用于充当内核与应用程序的桥梁作用。如果缓冲区设置的过小,那么将不能充分利用网络带宽,网络传输速度过慢。如果设置的过大,那么内存资源将很快用完,新的连接将不能建立。故我们需要知道TCP缓冲区的用途,才能正确的配置内存的大小,实现更高的并发。
TCP为了实现可靠性,每个报文都需要收到对应的ACK报文,如果在RTO(retransmission timeout)的时间间隔内都收不到对方ACK报文,那么发送方就会重发报文。故发送方在收到确认ACK报文前都需要保存发送内存在缓冲区,因为后面重发的时候需要用到。如果我们每次都在收到确认报文后,再发送下一个报文,其流程图如下:
我们知道在以太网中,最大可以传送的报文大小是1500字节,除掉TCP/IP的头部字节,每个报文的最大实际有效字节就1k字节左右(在TCP中叫MSS, Max Segment Size )。假设网络的RTT时间是10ms(可以通过ping得到),那么在这种方式下每秒只能发送1k*1000/10=100KB,显然传送速度非常的慢。
那么我们能不能批量发送,批量确认呢?TCP的滑动窗口机制就是用于解决这个问题的。接收方把它的处理能力告诉发送方,使其限制发送速度即可,这就是滑动窗口的由来。接收方根据它的缓冲区,可以计算出后续能够接收多少字节的报文,这个数字叫做接收窗口。当内核接收到报文时,必须用缓冲区存放它们,这样剩余缓冲区空间变小,接收窗口也就变小了;当进程调用 read 函数后,数据被读入了用户空间,内核缓冲区就被清空,这意味着主机可以接收更多的报文,接收窗口就会变大。因此,接收窗口并不是恒定不变的,那么怎么把时刻变化的窗口通知给发送方呢?TCP 报文头部中的窗口字段,就可以起到通知的作用。当发送方从报文中得到接收方的窗口大小时,就明白了最多能发送多少字节的报文,这个数字被称为发送方的发送窗口。如果不考虑拥塞控制,发送方的发送窗口就是接收方的接收窗口(由于报文有传输时延,t1 时刻的接收窗口在 t2 时刻才能到达发送端,因此这两个窗口并不完全等价)。
在TCP的报文头部中,有一个2字节的窗口字段,用于通知发送方能够一次接收方能够一次接收的数据大小。当接收端受到窗口大小的时候,就可以根据窗口大小调整一次批量发送的数据的数量,如下图所示:
但是表示窗口大小只有2个字节,最大只能表示65535个字节,为啥不是65536呢,因为TCP允许设置窗口大小为0,从而关闭窗口,对方会因为窗口大小为0而不在发送数据,这也是我在《TCP四次挥手调优》的博文中说的,导致FIN报文发送不出的原因所在。如果窗口设置成最大,那么就是65535,为了描述方便,就以64k来计算。那么在同样的RTT为10ms的网络中,最大也只有6.4MB的速度。这与我们动辄gb的网络,差距还是很大。那么我们能不能设置更大的窗口呢?
Linux(https://tools.ietf.org/html/rfc1323)提供了参数
cat /proc/sys/net/ipv4/tcp_window_scaling
1
当设置为1时,及开启了动态调整窗口大小的功能,最大可以达到1GB。
既然打开tcp_window_scaling动态调整滑动窗口的大小,那么能不能把窗口调整到最大1GB,那么在一个RTT的时间内,就可以发送1GB的数据,在RTT为10ms的网络中,带宽就可以达到100GB了,显然那是不可能的。
那有没有什么依据共linux调整窗口的大小呢?上文中提到窗口的大小与缓冲区正相关,那我们是不是可以通过设置缓冲区的上下限供linux动态调整缓冲区的大小呢?我们又可以基于什么原则设置缓冲区的大小呢?
TCP每发送一个报文,都要等收到ACK确认报文才能从发送缓冲区中删除,那些发送出去但还没有收到ACK确认的报文,我们称之为飞行报文。带宽*RTT得到的大小我们称为带宽时延积。由于发送缓冲区的大小决定了发送窗口的大小,而发送窗口的大小又决定了一次能够发送的数据的大小,而一次能够发送的数据的大小又决定了飞行报文的大小,而飞行报文的大小如果与带宽时延积相关,那么就可以最大化的利用网络带宽。故如果发送缓冲区的大小与带宽时延积相等,那么就可以最大化的利用网络带宽。
那么我们能不能通过linux的socket参数SO_SNDBUF参数设置缓冲区的大小呢?如果我们那么设置了,linux就不能动态的调整缓冲区的大小了,那么单机能够同时创建的连接数量就会非常有限,从而影响并发性,而且网络也会一直波动,缓冲区不能一直处于最佳的状态。其实linux提供了参数:
cat /proc/sys/net/ipv4/tcp_wmem
4096 87380 4194304
用于动态设置缓冲区的大小,例子中4096表示缓冲区的最小大小,4194304表示缓冲区的最大大小,87380 表示默认值。发送缓冲区的动态调整比较简单,当发送缓冲区的剩余空间充足的时候,可以减小发送缓冲区的大小,反之则增加缓冲区的大小。最小值一般就用4096即可,最大值我们可以设置成带宽时延积的大小。在高并发的场景中我们可以降低默认的缓冲区大小,这样可以支持更高的并发。
Linux也提供了参数:
cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4194304
用于设置接收缓冲区的动态调整范围,每个参数的意义与tcp_wmem类似。与发送缓冲区类似,也不能通过socket设置参数SO_RCVBUF,否则会关闭自动调节功能。默认值的设置与发送缓冲区也类似,高并发场景下可以调低其中。发送缓冲区的调节功能是自动开启的,而接收缓冲区Linux提供了参数
cat /proc/sys/net/ipv4/tcp_moderate_rcvbuf
1
默认值为1,表示开启接收缓冲区的动态调整功能。发送缓冲区自动调节的依据是待发送的数据,接收缓冲区由于只能被动地等待接收数据,它该如何自动调整呢?可以依据空闲系统内存的数量来调节接收窗口。如果系统的空闲内存很多,就可以把缓冲区增大一些,这样传给对方的接收窗口也会变大,因而对方的发送速度就会通过增加飞行报文来提升。反之,内存紧张时就会缩小缓冲区,这虽然会减慢速度,但可以保证更多的并发连接正常工作。
Linux提供了参数:
cat /proc/sys/net/ipv4/tcp_mem
3079776 4106368 6159552
用于设置可以用于TCP缓冲区的大小,当 TCP 内存小于第 1 个值时,不需要进行自动调节;在第 1 和第 2 个值之间时,内核开始调节接收缓冲区的大小;大于第 3 个值时,内核不再为 TCP 分配新内存,此时新连接是无法建立的,如果接收缓冲区满了,也无法接收新数据。需要注意的是tcp_mem是以page_size为单位(其值一般为4KB),而tcp_rmem与tcp_wmem是以Byte为单位。
Ubuntu环境下安装nodejs和npm_ubuntunanz node
tab:向右缩进shift+tab:向左缩进_idea多行缩进
1、求二叉树中的节点个数递归解法:(1)如果二叉树为空,节点个数为0(2)如果二叉树不为空,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1int NodeNum(BTNode * root){ if(root== NULL) // 递归出口 return 0; return NodeNum(root->lchild) + NodeNum(root->rchild) + 1;}2、求二叉树的深度递归解法:(1)如果二叉树为空,二叉_二叉树的递归算法
读研一年,初入交通领域,分享两个比较常用工具 :OSMNX &FMM路网处理使用OSMNX可以大幅减少代码工作量,FMM绑路效果我觉得很不错~1.OSMNX官方手册:OSMnx 1.1.1 — OSMnx 1.1.1 documentation安装:首页的安装教程十分简单,centos和ubuntu系统下都十分亲切,conda直接安装,记得换源!接口:在User reference中有十分详细的接口说明,按照教程安装con..._osmnx修改路网属性
1.1 亮度感应及曝光 1.1.1 感光宽容度从最明亮到最黑暗,假设人眼能够看到一定的范围,那么胶片(或CCD等电子感光器件)所能表现的远比人眼看到的范围小的多,而这个有限的范围就是感光宽容度。人眼的感光宽容度比胶片要高很多,而胶片的感光宽容度要比数码相机的ccd高出很多!了解这个概念之后,我们就不难了解,为什么在逆光的条件下,人眼能看清背光的建筑物以及耀眼的天空云彩。而一旦拍摄出
oracle 11g ORA-12514问题_oracle11g ora-12514
JVM通过Ergonomics技术已经尽可能的让jvm不要我们去操心底层的细节,而尝试提供给我们好的服务。但是,内存管理和gc并没有一个一劳永逸的方案。GC有可能成为性能的瓶颈。很多时候还是要程序员自己动手去做一些调优。以下简要介绍一些关键概念。JVM会自动选择使用server mode还是client mode。但是我们一样可以手工设置。java -server -cli...
{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云文件存储NAS是一个可共享访问,弹性扩展,高可靠,高性能的分布式文件系统。广泛应用于容器存储、大数据分析、Web 服务和内容管理、应用程序开发和测试、媒体..._检测文件夹变动并复制文件
1、关于QSplitter QSplitter类继承自QFrame类,也就是说该类是一个带有边框的可视部件。QSplitter类实现了分离器,分离器用于分离两个部件,用户可通过拖动部件之间的分界线来调整子部件的大小。2、在已创建好的布局中添加窗口分界线,demo已调试成功,效果如下:3、代码如下:#inc..._qt ui分隔线
1.设备2.实现思路及实物接线3.yolov5训练及UI设计代码编写4.arduino控制代码及讲解5.实现效果6.待改进思路。
c-二位数组赋值及二维指针使用欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入#include <stdio.h>void main(){int test3 = {{1, 1_c语言二维数组赋值给指针
题目背景给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。在杨辉三角中,每个数是它左上方和右上方的数的和。示例:输入: 5 输出:著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。解法一class Solution {public: vector<vector<int>> generate(int numRows) { vector<vector<int>> ans;