百万并发之 tcp_mem

 

在服务端,连接达到一定数量,诸如50W时,有些隐藏很深的问题,就不断的抛出来。 通过查看dmesg命令查看,发现大量TCP: too many of orphaned sockets错误,也很正常,下面到了需要调整tcp socket参数的时候了。

第一个需要调整的是tcp_rmem,即TCP读取缓冲区,单位为字节,查看默认值

  1. cat /proc/sys/net/ipv4/tcp_rmem
  2. 4096 87380 4161536

默认值为87380 byte ≈ 86K,最小为4096 byte=4K,最大值为4064K。

第二个需要调整的是tcp_wmem,发送缓冲区,单位是字节,默认值

  1. cat /proc/sys/net/ipv4/tcp_wmem
  2. 4096 16384 4161536

解释同上

第三个需要调整的tcp_mem,调整TCP的内存大小,其单位是页,1页等于4096字节。系统默认值:

  1. cat /proc/sys/net/ipv4/tcp_mem
  2. 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调整语句为:

  1. echo "net.ipv4.tcp_mem = 786432 2097152 3145728">> /etc/sysctl.conf
  2. echo "net.ipv4.tcp_rmem = 4096 4096 16777216">> /etc/sysctl.conf
  3. echo "net.ipv4.tcp_wmem = 4096 4096 16777216">> /etc/sysctl.conf

备注: 为了节省内存,设置tcp读、写缓冲区都为4K大小,tcp_mem三个值分别为3G 8G 16G,tcp_rmemtcp_wmem最大值也是16G。

目标达成

经过若干次的尝试,最终达到目标,1024000个持久连接。1024000数字是怎么得来的呢,两台物理机器各自发出64000个请求,两个配置为6G左右的centos测试端机器(绑定7个桥接或NAT连接)各自发出640007 = 448000。也就是 1024000 = (64000) + (64000) + (640007) + (64000*7), 共使用了16个网卡(物理网卡+虚拟网卡)。
终端输出

  1. ......
  2. online user 1023990
  3. online user 1023991
  4. online user 1023992
  5. online user 1023993
  6. online user 1023994
  7. online user 1023995
  8. online user 1023996
  9. online user 1023997
  10. online user 1023998
  11. online user 1023999
  12. 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 某刻输出信息:

  1. top - 17:23:17 up 18 min, 4 users, load average: 0.33, 0.12, 0.11
  2. Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
  3. 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
  4. Mem: 10693580k total, 6479980k used, 4213600k free, 22916k buffers
  5. Swap: 8323056k total, 0k used, 8323056k free, 80360k cached
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 2924 yongboy 20 0 82776 74m 508 R 51.3 0.7 3:53.95 server

执行vmstate:

  1. vmstat
  2. procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
  3. r b swpd free buff cache si so bi bo in cs us sy id wa st
  4. 0 0 0 2725572 23008 80360 0 0 21 2 1012 894 0 9 89 2 0

获取当前socket连接状态统计信息:

  1. cat /proc/net/sockstat
  2. sockets: used 1024380
  3. TCP: inuse 1024009 orphan 0 tw 0 alloc 1024014 mem 2
  4. UDP: inuse 11 mem 1
  5. UDPLITE: inuse 0
  6. RAW: inuse 0
  7. FRAG: inuse 0 memory 0

获取当前系统打开的文件句柄:

  1. sysctl -a | grep file
  2. fs.file-nr = 1025216 0 1048576
  3. fs.file-max = 1048576

此时任何类似于下面查询操作都是一个慢,等待若干时间还不见得执行完毕。

  1. netstat -nat|grep -i "8000"|grep ESTABLISHED|wc -l
  2. 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的更多相关文章

  1. 嵌入式linux驱动开发之给linux系统添加温度传感器模块

    忙了几天,终于可以让ds18b20在自己的开发板的linux系统上跑了!虽然ds18b20不是什么新鲜玩意,但是想想知己可以给linux系统添加模块了还是有点小鸡冻呢! 虽然说现在硬件的资源非常丰富而 ...

  2. 嵌入式Linux驱动开发之helloword心得

    自从选择了物联网这个专业,智能XX的字样牵动着每一个学习这个专业的孩子. 大家兴致勃勃的来到了学校,结果一切想象和自己的设想并不一样.想象中的各种智能般梦幻的场景变成了真实的高数/电路/模电等等诸如此 ...

  3. linux驱动开发之GCC问题

    最近正在学习驱动开发,进展到字符设备驱动开发阶段. 先不多说,首先把刚看的一篇学习驱动步骤的帖子记录如下: 1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. ...

  4. linux驱动开发之HelloWorld

    最近实习,公司项目搞的是平板开发,而我分配的任务是将驱动加载到内核中. 准备工作,必要知识了解:加载有两种方式,一种是动态加载和卸载即模块加载,另一种是直接编译进入内核:Linux内核把驱动程序划分为 ...

  5. Linux驱动开发之LED驱动

    首先讲下字符设备控制技术 : 大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力.比如: 改变波特率. 在用户空间,使用ioctl系统调用来控制设备,原型如下:int ioctl(i ...

  6. (56)Linux驱动开发之二

                                                                                             内核基础   1.li ...

  7. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  8. Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)

    本文将介绍网络连接建立的过程.收发包流程,以及当中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的server端程序.我们会先调用socket函 ...

  9. kernel笔记:TCP参数

    http://blog.chinaunix.net/uid-27119491-id-3346430.html 本文将介绍网络连接建立的过程.收发包流程,以及其中应用层.tcp层.ip层.设备层和驱动层 ...

随机推荐

  1. C++调用ffmpeg.exe提取视频帧

    有时候,我们获得一段视频,需要将其中的每一帧都提取出来,来进行一些相关的处理,这时候我们就可以需要用到ffmpeg.exe来进行视频帧的提取. ffmpeg简介:FFmpeg是一套可以用来记录.转换数 ...

  2. Linux搭建禅道

    1.开源版安装包下载(64位的下载64位,32位的选中32位) [root@iZbp~]# wget http://dl.cnezsoft.com/zentao/9.0.1/ZenTaoPMS.9.0 ...

  3. alpha冲刺(7/10)

    前言 队名:旅法师 作业链接 队长博客 燃尽图 会议 会议照片 会议内容 陈晓彬(组长) 今日进展: 召开会议 撰写博客 项目初步整合前端代码 问题困扰: 大家可能因为某些问题会联系卡在某个点很久,需 ...

  4. day01计算机基础

    今日内容 1.计算机初步认识 1.计算机认识 1. 计算机基础 1.1硬件:cpu/内存/硬盘/主板/网卡 1.2操作系统 linux:免费开源 windows mac 1.3解释器/编译器 补充:编 ...

  5. node 下less无法编译的问题

    vue+less的项目中,npm run dev不通过,提示以下错误: These dependencies were not found: * !!vue-style-loader!css-load ...

  6. JavaBasic_正则表达式

    就是符合一定规则的字符串 规则字符在java.util.regex.Pattern类中 字符转义\. 匹配.字符\* 匹配*字符\\ 匹配\字符\n 新行(换行)符 ('\u000A') \r 回车符 ...

  7. Java执行JavaScript代码

    Java执行JavaScript代码 这篇文章主要为大家详细介绍了Java执行JavaScript代码的具体操作方法,感兴趣的小伙伴们可以参考一下 我们要在Java中执行JavaScriptMetho ...

  8. Python教程:进击机器学习(五)--Scipy《转》

    Scipy简介 文件输入和输出scipyio 线性代数操作scipylinalg 快速傅里叶变换scipyfftpack 优化器scipyoptimize 统计工具scipystats Scipy简介 ...

  9. k8s学习笔记之九: Service Account

    第一章.前言 每一个用户对API资源进行操作都需要通经过以下三个步骤: 第一步:对客户端访问进行认证操作,确认是否具有访问k8s权限 token(共享秘钥) SSL(双向SSL认证) ....通过任何 ...

  10. win10环境下Android studio安装教程----亲测可用

    这段时间学习了一下Android的基本开发,发现Google已经停止了对eclipse的支持,并开发了自己的Android开发工具--Android Studio,于是想安装一下Android Stu ...