nproc是操作系统级别对每个用户创建的进程数的限制,在Linux下运行多线程时,每个线程的实现其实是一个轻量级的进程,对应的术语是:light weight process(LWP)。怎么知道一个用户创建了多少个进程呢,默认的ps是不显示全部进程的,需要‘-L' 才能看到所有的进程。
查看所有用户创建的进程数,使用命令:
# ps h -Led -o user | sort | uniq -c | sort -n
1 chrony
1 dbus
1 libstoragemgmt
1 nobody
2 avahi
5 nginx
6 polkitd
10 memcached
27 mysql
1071 root
查看root用户创建的进程数,使用命令:
# ps -o nlwp,pid,lwp,args -u root | sort -n
NLWP PID LWP COMMAND
1 27 27 [migration/3]
1 2828 2828 /sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/libexec/libvirt_leaseshelper
1 28 28 [ksoftirqd/3]
1 2902 2902 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
134 26155 26155 /usr/local/jdk1.8.0_11/bin/java -server -jar /usr/local/tomcat/school/school666.jar --spring.profiles.active=test
180 26330 26330 /usr/local/jdk1.8.0_11/bin/java -server -jar /usr/local/tomcat/smsy/school777.jar --spring.profiles.active=test
199 25967 25967 /usr/local/jdk1.8.0_11/bin/java -server -jar /usr/local/tomcat/bulu/bulu888.jar --spring.profiles.active=test
250 25780 25780 /usr/local/jdk1.8.0_11/bin/java -server -jar /usr/local/tomcat/private/private999.jar --spring.profiles.active=test
当日志出现以下情况中的一种时,需要修改nproc:
-
Cannot create GC thread. Out of system resources
-
java.lang.OutOfMemoryError: unable to create new native thread
(1)
ps -u produser –f
此方法是查看当前produser用户打开的进程数量。
但是,(1)方法在用户应用是多线程模式下不好使,使用此统计方法,统计出来的进程数量要小于限制值。那么应该如何查询,我们先来看一段官方文档 man 2 setrlimit:
image.png
因此在Linux主机上我们应该统计用户打开的进程线程的数量,ps命令需要加-L参数用于查看线程,所以给出下面的命令:
(2)
ps -u produser –Lf
大部分情况使(2)方法就能查看的结果。但是笔者要说的是⑵方法仍然存在问题,统计出来的进程数在某些情况下仍然小于限制值,再看一下上面的文档,其实nproc限制值是限制的real user创建的进程线程数。进程创建的时候存在real user和effective user两个属性,用ps命令统计的时候默认显示的是effective user的进程数,当进程的real user跟effective user不一致的时候会导致上面的命令统计的结果小于限制值。 上面-u参数查看的是effective user,因此这里再改进一下,使用-U参数查real user为produser的用户:
(3)
ps -U produser –Lf
这个命令也是根据实际案例发现的:我们生产上存在部分用户的crontab任务没有加标准输出和错误输出的重定向,同时系统的postfix服务没有打开,这样crontab任务输出会以邮件形式存放到/var/spool/postfix/maildrop目录,最终导致文件系统的inode使用率过高。一日我们工程师在对maildrop清理的时候不小心删除了maildrop目录,crond进程的子进程会hang住,结果用户进程数超过限制,导致其他用户应用出现问题、无法登录等问题。最开始使用的是⑵方法统计的线程数量,结果小于用户的限制值,后来发现crond进程在执行用户任务的时候会开辟一个CROND的子进程切换到对应用户执行相应的任务,其中这些CROND的子进程对应的effective user为root,real user为produser,如下所示:
image.png
因此当我们要统计用户打开的进程线程数的任务,一定要统计real user的进程线程数,下面的方法可以正确统计主机所有用户的进程线程数:
上面主要给大家介绍了用户nproc达到限制值时分析的方法。接着给大家介绍一个案例,主要谈谈用户nproc hard的默认值是怎么取到的。
一台1C2G的RHEL6版本虚拟机,用于制作虚拟机模板,在/etc/security/limits.d/90-nproc.conf修改了用户nproc的soft值,如下:
image.png
该配置设置了root用户的nproc的soft值为ulimited,其他用户的nproc的soft值为10240。然而当检查每个用户的nproc值的时候惊奇地发现用户的nproc的hard和soft值均为7387,如下:
image.png
这个值很奇怪,用户nproc的soft和hard值并不是10240,但是在其他主机上这个配置能够达到预期的值。经过分析,笔者认为上面的配置中由于并没有设置用户nproc的hard值,导致用户nproc的soft值受到hard值的限制,取不到预期的值,因此关键问题需要搞清楚hard值是由哪个因素决定的。笔者琢磨了一下,认为nproc的hard值是在内核获取到的,所以翻看了内核代码,果然在内核代码fork.c中发现端倪:
image.png
其中mempages是物理内存页的个数,PAGE_SIZE为4K,THREAD_SIZE在笔者的x86平台是16K,所以最后默认的nproc值为:
default_nproc = max_threads/2
= MemTotal(KB) / 256(KB)
即默认nproc大小取决于主机内存大小。在笔者2G内存(实际虚拟机内存为1877M,Hypervisor管理虚拟机有内存开销)的虚拟机上,计算一下:
default_nproc = 1877*1024/256 = 7508
由于kernel会占用一部分的内存,实际的nproc(本例中为7387)要比计算值稍小一些。笔者的案例中仅仅设置了用户nproc的soft值,所以用户的nproc的soft值被限制在default_nproc。因此上面例子中有两种解决方法:
-
评估需求,用户nproc的要是少于7387的话,就降低;
-
在配置文件中,设置上用户nproc的hard值为10240,通过提升hard值来满足预期。
因此各位看官今后要根据主机内存配置合理地设置用户nproc的值。
linux max_threads参数计算
内核threads线程数是一定的,具体是跟机器内存有关系
部分参数获取方法
PAGE_SIZE:getconf PAGE_SIZE 单位byte 页的大小 4096即4K
THREAD_SIZE:ulimit -s 8192 线程栈大小,单位byte 即8K
额定具体计算如下
max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8
mempages是物理内存页的个数;
mempages计算
mempages = 物理内存大小 ÷ PAGE_SIZE
例如:32G内存
mempages = 32174 * 1024 * 1024/4*1024 = 8236544 物理内存页的个数
max_threads = 8236544/(81024)/(41024)/8 = 514784
因为为了保证每个用户进程总数不至于超过一半内存fork_init()指定:
init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
即物理额定线程数为514784/2=257392
链接:https://www.jianshu.com/p/3726af3c9771
原文链接:
https://blog.csdn.net/odailidong/article/details/50561257
https://www.sohu.com/a/168794256_151779
网友评论