今天碰到很恶心的问题,就是宝塔里看到CPU和负载老100%,其实后面就是因为连接数太大造成的,我们需要扩容连接数,结果负载就减下来了。通过这次实践,也收藏了一些关于lunix命令,比如ulimit。接下来分享下:
Linux对于每个用户,系统限制其最大进程数。为提高性能,可以根据设备资源情况,设置各linux 用户的最大进程数
可以用ulimit -a 来显示当前的各种用户进程限制。
下面我把某linux用户的最大进程数设为10000个:
ulimit -u 10240
对于需要做许多 socket 连接并使它们处于打开状态的 Java 应用程序而言,
最好通过使用 ulimit -n xx 修改每个进程可打开的文件数,缺省值是 1024。
ulimit -n 4096 将每个进程可以打开的文件数目加大到4096,缺省为1024
其他建议设置成无限制(unlimited)的一些重要设置是:
数据段长度:ulimit -d unlimited
最大内存大小:ulimit -m unlimited
堆栈大小:ulimit -s unlimited
CPU 时间:ulimit -t unlimited
虚拟内存:ulimit -v unlimited
暂时地,适用于通过 ulimit 命令登录 shell 会话期间。
永久地,通过将一个相应的 ulimit 语句添加到由登录 shell 读取的文件中, 即特定于 shell 的用户资源文件,如:
1)、解除 Linux 系统的最大进程数和最大文件打开数限制:
vi /etc/security/limits.conf
# 添加如下的行
* soft noproc 11000
* hard noproc 11000
* soft nofile 4100
* hard nofile 4100
说明:* 代表针对所有用户,noproc 是代表最大进程数,nofile 是代表最大文件打开数
2)、让 SSH 接受 Login 程式的登入,方便在 ssh 客户端查看 ulimit -a 资源限制:
a、vi /etc/ssh/sshd_config
把 UserLogin 的值改为 yes,并把 # 注释去掉
b、重启 sshd 服务:
/etc/init.d/sshd restart
3)、修改所有 linux 用户的环境变量文件:
vi /etc/profile
ulimit -u 10000
ulimit -n 4096
ulimit -d unlimited
ulimit -m unlimited
ulimit -s unlimited
ulimit -t unlimited
ulimit -v unlimited
保存后运行#source /etc/profile 使其生效
/**************************************
有时候在程序里面需要打开多个文件,进行分析,系统一般默认数量是1024,(用ulimit -a可以看到)对于正常使用是够了,但是对于程序来讲,就太少了。
修改2个文件。
1./etc/security/limits.conf
vi /etc/security/limits.conf
加上:
* soft nofile 8192
* hard nofile 20480
2./etc/pam.d/login
session required /lib/security/pam_limits.so
/**********
另外确保/etc/pam.d/system-auth文件有下面内容
session required /lib/security/$ISA/pam_limits.so
这一行确保系统会执行这个限制。
/***********
3.一般用户的.bash_profile
#ulimit -n 1024
重新登陆ok
ulimit 的作用
ulimit:显示(或设置)用户可以使用的资源的限制(limit),这限制分为软限制(当前限制)和硬限制(上限),其中硬限制是软限制的上限值,应用程序在运行过程中使用的系统资源不超过相应的软限制,任何的超越都导致进程的终止。
参数 描述
ulimited 不限制用户可以使用的资源,但本设置对可打开的最大文件数(max open files)
和可同时运行的最大进程数(max user processes)无效
-a 列出所有当前资源极限
-c 设置core文件的最大值.单位:blocks
-d 设置一个进程的数据段的最大值.单位:kbytes
-f Shell 创建文件的文件大小的最大值,单位:blocks
-h 指定设置某个给定资源的硬极限。如果用户拥有 root 用户权限,可以增大硬极限。任何用户均可减少硬极限
-l 可以锁住的物理内存的最大值
-m 可以使用的常驻内存的最大值,单位:kbytes
-n 每个进程可以同时打开的最大文件数
-p 设置管道的最大值,单位为block,1block=512bytes
-s 指定堆栈的最大值:单位:kbytes
-S 指定为给定的资源设置软极限。软极限可增大到硬极限的值。如果 -H 和 -S 标志均未指定,极限适用于以上二者
-t 指定每个进程所使用的秒数,单位:seconds
-u 可以运行的最大并发进程数
-v Shell可使用的最大的虚拟内存,单位:kbytes
-x
范例1:
[root@localhost proc]# ulimit -a
core file size (blocks, -c) 100
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 2047
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 2047
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[root@localhost proc]#
输出的每一行由资源名字、(单位,ulimit命令的参数)、软限制组成。详细解释:
参数 描述
core file size core文件的最大值为100 blocks,
data seg size 进程的数据段可以任意大
file size 文件可以任意大
pending signals 最多有2047个待处理的信号
max locked memory 一个任务锁住的物理内存的最大值为32kB
max memory size 一个任务的常驻物理内存的最大值
open files 一个任务最多可以同时打开1024的文件
pipe size 管道的最大空间为4096字节
POSIX message queues POSIX的消息队列的最大值为819200字节
stack size 进程的栈的最大值为8192字节
cpu time 进程使用的CPU时间
max user processes 当前用户同时打开的进程(包括线程)的最大个数为2047
virtual memory 没有限制进程的最大地址空间
file locks 所能锁住的文件的最大个数没有限制
范例2:通过ulimit命令来限制文件的大小,从而导致拷贝命令的失败
[root@localhost]ls temp.txt
ls: temp.txt: 没有那个文件或目录
[root@localhost]ulimit -f 1 #设置创建文件的最大块(一块=512字节)
[root@localhost]cat a.c > temp.txt
文件大小超出限制
文件a.c的大小是5002字节,而我们设定的创建文件的大小是512字节x1块=512字节
1、修改用户进程可打开文件数限制
在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因為系统為每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。可使用ulimit命令查看系统允许当前用户进程打开的文件数限制:
[speng@as4 ~]$ ulimit -n
1024
这表示当前用户的每个进程最多允许同时打开1024个文件,这1024个文件中还得除去每个进程必然打开的标準输入,标準输出,标準错误,服务器监听socket,进程间通讯的unix域socket等文件,那麼剩下的可用於客户端socket连接的文件数就只有大概1024-10=1014个左右。也就是说缺省情况下,基於Linux的通讯程序最多允许同时1014个TCP并发连接。
对於想支持更高数量的TCP并发连接的通讯处理程序,就必须修改Linux对当前用户的进程同时打开的文件数量的软限制(soft limit)和硬限制(hardlimit)。其中软限制是指Linux在当前系统能够承受的范围内进一步限制用户同时打开的文件数;硬限制则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。通常软限制小於或等於硬限制。
修改上述限制的最简单的办法就是使用ulimit命令:
[speng@as4 ~]$ ulimit -n <file_num>
上述命令中,在<file_num>中指定要设置的单一进程允许打开的最大文件数。如果系统回显类似於"Operation notpermitted"之类的话,说明上述限制修改失败,实际上是因為在<file_num>中指定的数值超过了Linux系统对该用户打开文件数的软限製或硬限制。因此,就需要修改Linux系统对用户的关於打开文件数的软限制和硬限制。
第一步,修改/etc/security/limits.conf文件,在文件中添加如下行:
speng soft nofile 10240
speng hard nofile 10240
其中speng指定了要修改哪个用户的打开文件数限制,可用'*'号表示修改所有用户的限制;soft或hard指定要修改软限制还是硬限制;10240则指定了想要修改的新的限制值,即最大打开文件数(请注意软限制值要小於或等於硬限制)。修改完后保存文件。
第二步,修改/etc/pam.d/login文件,在文件中添加如下行:
session required /lib/security/pam_limits.so
这是告诉Linux在用户完成系统登录后,应该调用pam_limits.so模块来设置系统对该用户可使用的各种资源数量的最大限制(包括用户可打开的最大文件数限制),而pam_limits.so模块就会从/etc/security/limits.conf文件中读取配置来设置这些限制值。修改完后保存此文件。
第三步,查看Linux系统级的最大打开文件数限制,使用如下命令:
[speng@as4 ~]$ cat /proc/sys/fs/file-max
12158
这表明这台Linux系统最多允许同时打开(即包含所有用户打开文件数总和)12158个文件,是Linux系统级硬限制,所有用户级的打开文件数限制都不应超过这个数值。通常这个系统级硬限制是Linux系统在啟动时根据系统硬件资源状况计算出来的最佳的最大同时打开文件数限制,如果没有特殊需要,不应该修改此限制,除非想為用户级打开文件数限制设置超过此限制的值。修改此硬限制的方法是修改/etc/rc.local脚本,在脚本中添加如下行:
echo 22158 > /proc/sys/fs/file-max
这是让Linux在啟动完成后强行将系统级打开文件数硬限制设置為22158。修改完后保存此文件。
完成上述步骤后重啟系统,一般情况下就可以将Linux系统对指定用户的单一进程允许同时打开的最大文件数限制设為指定的数值。如果重啟后用ulimit-n命令查看用户可打开文件数限制仍然低於上述步骤中设置的最大值,这可能是因為在用户登录脚本/etc/profile中使用ulimit -n命令已经将用户可同时打开的文件数做了限制。由於通过ulimit-n修改系统对用户可同时打开文件的最大数限制时,新修改的值只能小於或等於上次ulimit-n设置的值,因此想用此命令增大这个限制值是不可能的。所以,如果有上述问题存在,就只能去打开/etc/profile脚本文件,在文件中查找是否使用了ulimit-n限制了用户可同时打开的最大文件数量,如果找到,则删除这行命令,或者将其设置的值改為合适的值,然后保存文件,用户退出并重新登录系统即可。
通过上述步骤,就為支持高并发TCP连接处理的通讯处理程序解除关於打开文件数量方面的系统限制。
2、修改网络内核对TCP连接的有关限制
在Linux上编写支持高并发TCP连接的客户端通讯处理程序时,有时会发现儘管已经解除了系统对用户同时打开文件数的限制,但仍会出现并发TCP连接数增加到一定数量时,再也无法成功建立新的TCP连接的现象。出现这种现在的原因有多种。
第一种原因可能是因為Linux网络内核对本地端口号范围有限制。此时,进一步分析為什麼无法建立TCP连接,会发现问题出在connect()调用返回失败,查看系统错误提示消息是"Can't assign requestedaddress"。同时,如果在此时用tcpdump工具监视网络,会发现根本没有TCP连接时客户端发SYN包的网络流量。这些情况说明问题在於本地Linux系统内核中有限制。其实,问题的根本原因在於Linux内核的TCP/IP协议实现模块对系统中所有的客户端TCP连接对应的本地端口号的范围进行了限制(例如,内核限製本地端口号的范围為1024~32768之间)。当系统中某一时刻同时存在太多的TCP客户端连接时,由於每个TCP客户端连接都要佔用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),如果现有的TCP客户端连接已将所有的本地端口号佔满,则此时就无法為新的TCP客户端连接分配一个本地端口号了,因此系统会在这种情况下在connect()调用中返回失败,并将错误提示消息设為"Can't assignrequested address"。有关这些控制逻辑可以查看Linux内核源代码,以linux2.6内核為例,可以查看tcp_ipv4.c文件中如下函数:
static int tcp_v4_hash_connect(struct sock *sk)
请注意上述函数中对变量sysctl_local_port_range的访问控制。变量sysctl_local_port_range的初始化则是在tcp.c文件中的如下函数中设置:
void __init tcp_init(void)
内核编译时默认设置的本地端口号范围可能太小,因此需要修改此本地端口范围限制。
第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
net.ipv4.ip_local_port_range = 1024 65000
这表明将系统对本地端口范围限制设置為1024~65000之间。请注意,本地端口范围的最小值必须大於或等於1024;而端口范围的最大值则应小於或等於65535。修改完后保存此文件。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明新的本地端口范围设置成功。如果按上述端口范围进行设置,则理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。
第二种无法建立TCP连接的原因可能是因為Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制。此时程序会表现為在connect()调用中阻塞,如同死机,如果用tcpdump工具监视网络,也会发现根本没有TCP连接时客户端发SYN包的网络流量。由於IP_TABLE防火墙在内核中会对每个TCP连接的状态进行跟踪,跟踪信息将会放在位於内核内存中的conntrackdatabase中,这个数据库的大小有限,当系统中存在过多的TCP连接时,数据库容量不足,IP_TABLE无法為新的TCP连接建立跟踪信息,於是表现為在connect()调用中阻塞。此时就必须修改内核对最大跟踪的TCP连接数的限制,方法同修改内核对本地端口号范围的限制是类似的:
第一步,修改/etc/sysctl.conf文件,在文件中添加如下行:
net.ipv4.ip_conntrack_max = 10240
这表明将系统对最大跟踪的TCP连接数限制设置為10240。请注意,此限制值要尽量小,以节省对内核内存的佔用。
第二步,执行sysctl命令:
[speng@as4 ~]$ sysctl -p
如果系统没有错误提示,就表明系统对新的最大跟踪的TCP连接数限制修改成功。如果按上述参数进行设置,则理论上单独一个进程最多可以同时建立10000多个TCP客户端连接。
网友评论文明上网理性发言已有0人参与
发表评论: