linux百万并发之 tcp_mem
百万并发之 tcp_mem
在服务端,连接达到一定数量,诸如50W时,有些隐藏很深的问题,就不断的抛出来。 通过查看dmesg命令查看,发现大量TCP: too many of orphaned sockets错误,也很正常,下面到了需要调整tcp socket参数的时候了。
第一个需要调整的是tcp_rmem,即TCP读取缓冲区,单位为字节,查看默认值
- cat /proc/sys/net/ipv4/tcp_rmem
- 4096 87380 4161536
默认值为87380 byte ≈ 86K,最小为4096 byte=4K,最大值为4064K。
第二个需要调整的是tcp_wmem,发送缓冲区,单位是字节,默认值
- cat /proc/sys/net/ipv4/tcp_wmem
- 4096 16384 4161536
解释同上
第三个需要调整的tcp_mem,调整TCP的内存大小,其单位是页,1页等于4096字节。系统默认值:
- cat /proc/sys/net/ipv4/tcp_mem
- 932448 1243264 1864896
tcp_mem(3个INTEGER变量):low, pressure, high
- low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。
- pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。
- high:允许所有tcp sockets用于排队缓冲数据报的页面量,当内存占用超过此值,系统拒绝分配socket,后台日志输出“TCP: too many of orphaned sockets”。
一般情况下这些值是在系统启动时根据系统内存数量计算得到的。 根据当前tcp_mem最大内存页面数是1864896,当内存为(1864896*4)/1024K=7284.75M时,系统将无法为新的socket连接分配内存,即TCP连接将被拒绝。
实际测试环境中,据观察大概在99万个连接左右的时候(零头不算),进程被杀死,触发out of socket memory错误(dmesg命令查看获得)。每一个连接大致占用7.5K内存(下面给出计算方式),大致可算的此时内存占用情况(990000 * 7.5 / 1024K = 7251M)。
这样和tcp_mem最大页面值数量比较吻合,因此此值也需要修改。
三个TCP调整语句为:
- echo "net.ipv4.tcp_mem = 786432 2097152 3145728">> /etc/sysctl.conf
- echo "net.ipv4.tcp_rmem = 4096 4096 16777216">> /etc/sysctl.conf
- echo "net.ipv4.tcp_wmem = 4096 4096 16777216">> /etc/sysctl.conf
备注: 为了节省内存,设置tcp读、写缓冲区都为4K大小,tcp_mem
三个值分别为3G 8G 16G,tcp_rmem
和tcp_wmem
最大值也是16G。
目标达成
经过若干次的尝试,最终达到目标,1024000个持久连接。1024000数字是怎么得来的呢,两台物理机器各自发出64000个请求,两个配置为6G左右的centos测试端机器(绑定7个桥接或NAT连接)各自发出640007 = 448000。也就是 1024000 = (64000) + (64000) + (640007) + (64000*7), 共使用了16个网卡(物理网卡+虚拟网卡)。
终端输出
- ......
- online user 1023990
- online user 1023991
- online user 1023992
- online user 1023993
- online user 1023994
- online user 1023995
- online user 1023996
- online user 1023997
- online user 1023998
- online user 1023999
- online user 1024000
在线用户目标达到1024000个!
服务器状态信息
服务启动时内存占用:
total used free shared buffers cached
Mem: 10442 271 10171 0 22 78
-/+ buffers/cache: 171 10271
Swap: 8127 0 8127
系统达到1024000个连接后的内存情况(执行三次 free -m 命令,获取三次结果):
total used free shared buffers cached
Mem: 10442 7781 2661 0 22 78
-/+ buffers/cache: 7680 2762
Swap: 8127 0 8127 total used free shared buffers cached
Mem: 10442 7793 2649 0 22 78
-/+ buffers/cache: 7692 2750
Swap: 8127 0 8127 total used free shared buffers cached
Mem: 10442 7804 2638 0 22 79
-/+ buffers/cache: 7702 2740
Swap: 8127 0 8127
这三次内存使用分别是7680,7692,7702,这次不取平均值,取一个中等偏上的值,定为7701M。那么程序接收1024000个连接,共消耗了 7701M-171M = 7530M内存, 7530M*1024K / 1024000 = 7.53K, 每一个连接消耗内存在为7.5K左右,这和在连接达到512000时所计算较为吻合。
虚拟机运行Centos内存占用,不太稳定,但一般相差不大,以上数值,仅供参考。
执行top -p 某刻输出信息:
- top - 17:23:17 up 18 min, 4 users, load average: 0.33, 0.12, 0.11
- Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
- Cpu(s): 0.2%us, 6.3%sy, 0.0%ni, 80.2%id, 0.0%wa, 4.5%hi, 8.8%si, 0.0%st
- Mem: 10693580k total, 6479980k used, 4213600k free, 22916k buffers
- Swap: 8323056k total, 0k used, 8323056k free, 80360k cached
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 2924 yongboy 20 0 82776 74m 508 R 51.3 0.7 3:53.95 server
执行vmstate:
- vmstat
- procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
- r b swpd free buff cache si so bi bo in cs us sy id wa st
- 0 0 0 2725572 23008 80360 0 0 21 2 1012 894 0 9 89 2 0
获取当前socket连接状态统计信息:
- cat /proc/net/sockstat
- sockets: used 1024380
- TCP: inuse 1024009 orphan 0 tw 0 alloc 1024014 mem 2
- UDP: inuse 11 mem 1
- UDPLITE: inuse 0
- RAW: inuse 0
- FRAG: inuse 0 memory 0
获取当前系统打开的文件句柄:
- sysctl -a | grep file
- fs.file-nr = 1025216 0 1048576
- fs.file-max = 1048576
此时任何类似于下面查询操作都是一个慢,等待若干时间还不见得执行完毕。
- netstat -nat|grep -i "8000"|grep ESTABLISHED|wc -l
- netstat -n | grep -i "8000" | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
以上两个命令在二三十分钟过去了,还未执行完毕,只好停止。
小结
本次从头到尾的测试,所需要有的linux系统需要调整的参数也就是那么几个,汇总一下:
1
2
3
4
5
6
7
8
|
echo "* - nofile 1048576" >> /etc/security/limits .conf echo "fs.file-max = 1048576" >> /etc/sysctl .conf echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl .conf echo "net.ipv4.tcp_mem = 786432 2097152 3145728" >> /etc/sysctl .conf echo "net.ipv4.tcp_rmem = 4096 4096 16777216" >> /etc/sysctl .conf echo "net.ipv4.tcp_wmem = 4096 4096 16777216" >> /etc/sysctl .conf |
其它没有调整的参数,仅仅因为它们暂时对本次测试没有带来什么影响,实际环境中需要结合需要调整类似于SO_KEEPALIVE、tcpmax_orphans等大量参数。
linux百万并发之 tcp_mem的更多相关文章
- 嵌入式linux驱动开发之给linux系统添加温度传感器模块
忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢! 虽然说现在硬件的资源非常丰富而 ...
- 嵌入式Linux驱动开发之helloword心得
自从选择了物联网这个专业,智能XX的字样牵动着每一个学习这个专业的孩子. 大家兴致勃勃的来到了学校,结果一切想象和自己的设想并不一样.想象中的各种智能般梦幻的场景变成了真实的高数/电路/模电等等诸如此 ...
- linux驱动开发之GCC问题
最近正在学习驱动开发,进展到字符设备驱动开发阶段. 先不多说,首先把刚看的一篇学习驱动步骤的帖子记录如下: 1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. ...
- linux驱动开发之HelloWorld
最近实习,公司项目搞的是平板开发,而我分配的任务是将驱动加载到内核中. 准备工作,必要知识了解:加载有两种方式,一种是动态加载和卸载即模块加载,另一种是直接编译进入内核:Linux内核把驱动程序划分为 ...
- Linux驱动开发之LED驱动
首先讲下字符设备控制技术 : 大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力.比如: 改变波特率. 在用户空间,使用ioctl系统调用来控制设备,原型如下:int ioctl(i ...
- (56)Linux驱动开发之二
内核基础 1.li ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)
本文将介绍网络连接建立的过程.收发包流程,以及当中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的server端程序.我们会先调用socket函 ...
- kernel笔记:TCP参数
http://blog.chinaunix.net/uid-27119491-id-3346430.html 本文将介绍网络连接建立的过程.收发包流程,以及其中应用层.tcp层.ip层.设备层和驱动层 ...
随机推荐
- C++调用ffmpeg.exe提取视频帧
有时候,我们获得一段视频,需要将其中的每一帧都提取出来,来进行一些相关的处理,这时候我们就可以需要用到ffmpeg.exe来进行视频帧的提取. ffmpeg简介:FFmpeg是一套可以用来记录.转换数 ...
- Linux搭建禅道
1.开源版安装包下载(64位的下载64位,32位的选中32位) [root@iZbp~]# wget http://dl.cnezsoft.com/zentao/9.0.1/ZenTaoPMS.9.0 ...
- alpha冲刺(7/10)
前言 队名:旅法师 作业链接 队长博客 燃尽图 会议 会议照片 会议内容 陈晓彬(组长) 今日进展: 召开会议 撰写博客 项目初步整合前端代码 问题困扰: 大家可能因为某些问题会联系卡在某个点很久,需 ...
- day01计算机基础
今日内容 1.计算机初步认识 1.计算机认识 1. 计算机基础 1.1硬件:cpu/内存/硬盘/主板/网卡 1.2操作系统 linux:免费开源 windows mac 1.3解释器/编译器 补充:编 ...
- node 下less无法编译的问题
vue+less的项目中,npm run dev不通过,提示以下错误: These dependencies were not found: * !!vue-style-loader!css-load ...
- JavaBasic_正则表达式
就是符合一定规则的字符串 规则字符在java.util.regex.Pattern类中 字符转义\. 匹配.字符\* 匹配*字符\\ 匹配\字符\n 新行(换行)符 ('\u000A') \r 回车符 ...
- Java执行JavaScript代码
Java执行JavaScript代码 这篇文章主要为大家详细介绍了Java执行JavaScript代码的具体操作方法,感兴趣的小伙伴们可以参考一下 我们要在Java中执行JavaScriptMetho ...
- Python教程:进击机器学习(五)--Scipy《转》
Scipy简介 文件输入和输出scipyio 线性代数操作scipylinalg 快速傅里叶变换scipyfftpack 优化器scipyoptimize 统计工具scipystats Scipy简介 ...
- k8s学习笔记之九: Service Account
第一章.前言 每一个用户对API资源进行操作都需要通经过以下三个步骤: 第一步:对客户端访问进行认证操作,确认是否具有访问k8s权限 token(共享秘钥) SSL(双向SSL认证) ....通过任何 ...
- win10环境下Android studio安装教程----亲测可用
这段时间学习了一下Android的基本开发,发现Google已经停止了对eclipse的支持,并开发了自己的Android开发工具--Android Studio,于是想安装一下Android Stu ...