原文地址:http://joyexpr.com/2013/11/22/c100k-4-kernel-tuning/

早期的系统,系统资源包括CPU、内存等都是非常有限的,系统为了保持公平,默认要限制进程对资源的使用情况。由于Linux的默认内核配置无法满足C100K的要求,因此需要对其进行适当的调优。

我们可以通过 ulimit 查看一下典型的机器默认的限制情况:

  1. $ ulimit -a
  2. core file size (blocks, -c) 0
  3. data seg size (kbytes, -d) unlimited
  4. scheduling priority (-e) 0
  5. file size (blocks, -f) unlimited
  6. pending signals (-i) 204800
  7. max locked memory (kbytes, -l) 32
  8. max memory size (kbytes, -m) unlimited
  9. open files (-n) 1024
  10. pipe size (512 bytes, -p) 8
  11. POSIX message queues (bytes, -q) 819200
  12. real-time priority (-r) 0
  13. stack size (kbytes, -s) 10240
  14. cpu time (seconds, -t) unlimited
  15. max user processes (-u) 204800
  16. virtual memory (kbytes, -v) unlimited
  17. file locks (-x) unlimited

比如其中的 open files,默认一个进程能打开的文件句柄数量为1024,对于一些需要大量文件句柄的程序,如web服务器、数据库程序等,1024往往是不够用的,在句柄使用完毕的时候,系统就会频繁出现emfile错误。

俗话说:一个巴掌拍不响,要完成 C100K 的目标,需要服务器端与客户端的紧密配合,下面将分别对这二者的调优进行介绍。

客户端

1:文件句柄数量受限

在Linux平台上,无论是编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,由于每个TCP连接都要创建一个socket句柄,而每个socket句柄同时也是一个文件句柄,所以其最高并发数量要受到系统对用户单一进程同时可打开文件数量的限制以及整个系统可同时打开的文件数量限制。

1.1:单一进程的文件句柄数量受限

我们可以ulimit命令查看当前用户进程可打开的文件句柄数限制:

  1. [root@localhost ~]# ulimit -n
  2. 1024

这表示当前用户的每个进程最多允许同时打开1024个文件,除去每个进程必然打开的标准输入、标准输出、标准错误、服务器监听socket、进程间通讯的unix域socket等文件,剩下的可用于客户端socket连接的文件数就只有大概1024-10=1014个左右。也就是说,在默认情况下,基于Linux的通讯程序最多允许同时1014个TCP并发连接。

对于想支持更高数量的TCP并发连接的通讯处理程序,就必须修改Linux对当前用户的进程可同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。其中:

  • 软限制是指Linux在当前系统能够承受的范围内进一步限制用户能同时打开的文件数。
  • 硬限制是指根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。

通常软限制小于或等于硬限制,可通过ulimit命令查看软限制和硬限制:

  1. [root@localhost ~]# ulimit -Sn
  2. 1024
  3. [root@localhost ~]# ulimit -Hn
  4. 4096

修改单一进程能同时打开的文件句柄数有2种方法:

1、直接使用ulimit命令,如:

  1. [root@localhost ~]# ulimit -n 1048576

执行成功之后,ulimit n、Sn、Hn的值均会变为1048576。但该方法设置的值只会在当前终端有效,且设置的值不能高于方法2中设置的值。

2、对 /etc/security/limits.conf 文件,添加或修改:

  1. * soft nofile 1048576
  2. * hard nofile 1048576

其中,

  • * 代表对所有用户有效,若仅想针对某个用户,可替换星号。
  • soft即软限制,它只是一个警告值。
  • hard代表硬限制,是一个真正意义的阈值,超过就会报错。
  • nofile表示打开文件的最大数量。
  • 1048576 = 1024 * 1024,为什么要取这个值呢?因为

在linux kernel 2.6.25之前通过ulimit -n(setrlimit(RLIMIT_NOFILE))设置每个进程的最大打开文件句柄数不能超过NR_OPEN(1024*1024),也就是100多w(除非重新编译内核),而在25之后,内核导出了一个sys接口可以修改这个最大值(/proc/sys/fs /nr_open).具体的changelog在https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=9cfe015aa424b3c003baba3841a60dd9b5ad319b

注意文件保存之后,需要注销或重启系统方能生效。

1.2:整个系统的文件句柄数量受限

解决完单一进程的文件句柄数量受限问题后,还要解决整个系统的文件句柄数量受限问题。我们可通过以下命令查看Linux系统级的最大打开文件数限制:

  1. [root@localhost ~]# cat /proc/sys/fs/file-max
  2. 98957

file-max表示系统所有进程最多允许同时打开的文件句柄数,是Linux系统级硬限制。通常,这个系统硬限制是Linux系统在启动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不应该修改此限制。

要修改它,需要对 /etc/sysctl.conf 文件,增加一行内容:

  1. fs.file-max = 1048576

保存成功后,需执行下面命令使之生效:

  1. [root@localhost ~]# sysctl -p

2:端口数量受限

解决完文件句柄数量受限的问题后,就要解决IP端口数量受限的问题了。一般来说,对外提供请求的服务端不用考虑端口数量问题,只要监听某一个端口即可。可客户端要模拟大量的用户对服务端发起TCP请求,而每一个请求都需要一个端口,为了使一个客户端尽可能地模拟更多的用户,也就要使客户端拥有更多可使用的端口。

由于端口为16进制,即最大端口数为2的16次方65536(0-65535)。在Linux系统里,1024以下端口只有超级管理员用户(如root)才可以使用,普通用户只能使用大于等于1024的端口值。

我们可以通过以下命令查看系统提供的默认的端口范围:

  1. [root@localhost ~]# cat /proc/sys/net/ipv4/ip_local_port_range
  2. 32768 61000

即只有61000-32768=28232个端口可以使用,即单个IP对外只能同时发送28232个TCP请求。

修改方法有以下2种:

1、执行以下命令:

  1. echo "1024 65535"> /proc/sys/net/ipv4/ip_local_port_range

该方法立即生效,但重启后会失效。

2、修改 /etc/sysctl.conf 文件,增加一行内容:

  1. net.ipv4.ip_local_port_range = 1024 65535

保存成功后,需执行下面命令使之生效:

  1. [root@localhost ~]# sysctl -p

修改成功后,可用端口即增加到65535-1024=64511个,即单个客户端机器只能同时模拟64511个用户。要想突破这个限制,只能给该客户端增加IP地址,这样即可相应成倍地增加可用IP:PORT数。具体可参考yongboy的这篇文章

服务端

1:文件描述符数量受限

同客户端的问题1。

2:TCP参数调优

要想提高服务端的性能,以达到我们高并发的目的,需要对系统的TCP参数进行适当的修改优化。

方法同样是修改 /etc/sysctl.conf 文件,增加以下内容:

  1. net.ipv4.tcp_tw_reuse = 1

当服务器需要在大量TCP连接之间切换时,会产生大量处于TIME_WAIT状态的连接。TIME_WAIT意味着连接本身是关闭的,但资源还没有释放。将net_ipv4_tcp_tw_reuse设置为1是让内核在安全时尽量回收连接,这比重新建立新连接要便宜得多。

  1. net.ipv4.tcp_fin_timeout = 15

这是处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。

  1. net.core.rmem_max = 16777216
  2. net.core.wmem_max = 16777216

提高TCP的最大缓冲区大小,其中:

net.core.rmem_max:表示接收套接字缓冲区大小的最大值(以字节为单位)。

net.core.wmem_max:表示发送套接字缓冲区大小的最大值(以字节为单位)。

  1. net.ipv4.tcp_rmem = 4096 87380 16777216
  2. net.ipv4.tcp_wmem = 4096 65536 16777216

提高Linux内核自动对socket缓冲区进行优化的能力,其中:

net.ipv4.tcp_rmem:用来配置读缓冲的大小,第1个值为最小值,第2个值为默认值,第3个值为最大值。

net.ipv4.tcp_wmem:用来配置写缓冲的大小,第1个值为最小值,第2个值为默认值,第3个值为最大值。

  1. net.core.netdev_max_backlog = 4096

每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。默认为1000。

  1. net.core.somaxconn = 4096

表示socket监听(listen)的backlog上限。什么是backlog呢?backlog就是socket的监听队列,当一个请求(request)尚未被处理或建立时,他会进入backlog。而socket server可以一次性处理backlog中的所有请求,处理后的请求不再位于监听队列中。当server处理请求较慢,以至于监听队列被填满后,新来的请求会被拒绝。默认为128。

  1. net.ipv4.tcp_max_syn_backlog = 20480

表示SYN队列的长度,默认为1024,加大队列长度为8192,可以容纳更多等待连接的网络连接数。

  1. net.ipv4.tcp_syncookies = 1

表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭。

  1. net.ipv4.tcp_max_tw_buckets = 360000

表示系统同时保持TIME_WAIT套接字的最大数量,如果超过这个数字,TIME_WAIT套接字将立刻被清除并打印警告信息。默认为180000。

  1. net.ipv4.tcp_no_metrics_save = 1

一个tcp连接关闭后,把这个连接曾经有的参数比如慢启动门限snd_sthresh、拥塞窗口snd_cwnd,还有srtt等信息保存到dst_entry中,只要dst_entry没有失效,下次新建立相同连接的时候就可以使用保存的参数来初始化这个连接。

  1. net.ipv4.tcp_syn_retries = 2

表示在内核放弃建立连接之前发送SYN包的数量,默认为4。

  1. net.ipv4.tcp_synack_retries = 2

表示在内核放弃连接之前发送SYN+ACK包的数量,默认为5。

完整的TCP参数调优配置如下所示:

  1. net.ipv4.tcp_tw_reuse = 1
  2. net.ipv4.tcp_fin_timeout = 15
  3. net.core.rmem_max = 16777216
  4. net.core.wmem_max = 16777216
  5. net.ipv4.tcp_rmem = 4096 87380 16777216
  6. net.ipv4.tcp_wmem = 4096 65536 16777216
  7. net.core.netdev_max_backlog = 4096
  8. net.core.somaxconn = 4096
  9. net.ipv4.tcp_max_syn_backlog = 20480
  10. net.ipv4.tcp_syncookies = 1
  11. net.ipv4.tcp_max_tw_buckets = 360000
  12. net.ipv4.tcp_no_metrics_save = 1
  13. net.ipv4.tcp_syn_retries = 2
  14. net.ipv4.tcp_synack_retries = 2

其它一些参数

  1. vm.min_free_kbytes = 65536

用来确定系统开始回收内存的阀值,控制系统的空闲内存。值越高,内核越早开始回收内存,空闲内存越高。

  1. vm.swappiness = 0

控制内核从物理内存移出进程,移到交换空间。该参数从0到100,当该参数=0,表示只要有可能就尽力避免交换进程移出物理内存;该参数=100,这告诉内核疯狂的将数据移出物理内存移到swap缓存中。

大战C100K之-Linux内核调优篇--转载的更多相关文章

  1. Linux网卡调优篇-禁用ipv6与优化socket缓冲区大小

    Linux网卡调优篇-禁用ipv6与优化socket缓冲区大小 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   一般在内网环境中,我们几乎是用不到IPV6,因此我们没有必要把多不 ...

  2. Linux内核调优参数说明

    该脚本是我常用的系统安装后执行脚本,包括开机启动服务.内核.SSH优化. !/bin/sh 服务优化,(sshd.network.crond.syslog.rsyslog)服务保持默认开机启动 Ser ...

  3. linux内核调优参考

    对于新部署的机器,需要做一些基本的调优操作,以更改一些默认配置带来的性能问题 1 修改打开文件数 root@mysql:/data/tools/db# vim /etc/security/limits ...

  4. (转)linux内核调优参数对比和解释

    [net] ######################## cat /proc/sys/net/ipv4/tcp_syncookies # 默认值:1 # 作用:是否打开SYN Cookie功能,该 ...

  5. linux内核调优详解

    cat > /etc/sysctl.conf << EOF net.ipv4.ip_forward = net.ipv4.conf.all.rp_filter = net.ipv4. ...

  6. Linux内核调优部分参数说明

    #接收套接字缓冲区大小的默认值(以字节为单位). net.core.rmem_default = 262144 #接收套接字缓冲区大小的最大值(以字节为单位). net.core.rmem_max = ...

  7. Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio”

      Linux虚拟内存(swap)调优篇-“swappiness”,“vm.dirty_background_ratio”和“vm.dirty_ratio” 作者:尹正杰 版权声明:原创作品,谢绝转载 ...

  8. Perf -- Linux下的系统性能调优工具,第 2 部分 特殊用法以及内核调优示例

    https://www.ibm.com/developerworks/cn/linux/l-cn-perf2/ 本文内容简介 之前介绍了 perf 最常见的一些用法,关注于 Linux 系统上应用程序 ...

  9. 大数据集群Linux CentOS 7.6 系统调优篇

    大数据集群Linux CentOS 7.6 系统调优篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.设置主机hosts文件 1>.修改主机名 [root@node100 ...

随机推荐

  1. 生成ssh公有密钥而且注冊到Github Generate ssh rsa keys and register public key on Github

    私有密钥和公有密钥是成对的两个文件,私有文件保存在自己的本机,公有密钥保存到还有一端的server,站点等. github就是一种站点. 仅仅有保存了私有密钥的机器才干訪问远程的server等. 使用 ...

  2. Qt源码编译

    Qt源码编译 eryar@163.com Key words. Qt, 源码编译 1.Introduction 随着Qt版本升级,源码编译出来的库体积越来越大.如果只是用Qt来做GUI,Qt提供的预编 ...

  3. CDQZ 0003:jubeeeeeat

    0003:jubeeeeeat 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  256000kB 描述 众所周知,LZF很喜欢打一个叫Jubeat的游戏.这是个音乐游戏,游戏界面是 ...

  4. 分享一个js加密的几种方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. BZOJ3994: [SDOI2015]约数个数和(莫比乌斯反演)

    Description  设d(x)为x的约数个数,给定N.M,求     Input 输入文件包含多组测试数据. 第一行,一个整数T,表示测试数据的组数. 接下来的T行,每行两个整数N.M. Out ...

  6. 小米开源文件管理器MiCodeFileExplorer-源码研究(5)-AsyncTask异步任务

    说明:本文的文字和代码,主要来自于网上的2篇文章. 第4篇的时候,提到了异步任务AsyncTask. 网上找了2篇文章学习下,copy网友的代码,稍微改了几个字,运行成功了. 在开发Android移动 ...

  7. 24.Node.js Stream(流)

    转自:http://www.runoob.com/nodejs/nodejs-stream.html Stream 是一个抽象接口,Node 中有很多对象实现了这个接口.例如,对http 服务器发起请 ...

  8. IIS6下AD域设置

    简介:IIS6下AD域设置 IIS6下AD域设置 http://files.cnblogs.com/files/KingUp/AD%E5%9F%9F%E8%AE%BE%E7%BD%AE.rar

  9. Day2下午解题报告

    预计分数:100+100+30=230 实际分数:100+100+30=230人品爆发&&智商爆发&&手感爆发 T3数据好水,,要是把数组开大一点的话还能多得10分,, ...

  10. Android手机间使用socket进行文件互传实例

    这是一个Android手机间文件传输的例子,两个手机同时装上此app,然后输入接收端的ip,选择文件,可以多选,点确定,就发送到另一个手机,一个简单快捷文件快传实例.可以直接运用到项目中. 下面是文件 ...