
问题

Caused by: java.lang.OutOfMemoryError: unable to create new native thread
这是困扰了我们一个很久的OOM问题,经常在一个节点上面多服务压力上来时出现,表面上是一个程序OOM,但具体又是里面的一个分支 线程问题。
出现的症状是不只是说一个服务,是跑在同一个节点上的所有服务而且是需要创建新线程的服务都出现无法创建新线程的异常日志,从节点的资源上看CPU和内存资源都还比较充足,只使用到了一半。
我们查看这个节点上的总线程数如下图趋势:

经常性出现,从经验上来看节点的总线程数到达32000后无不例外就有服务出现了unable to create new native thread的异常,而且比较坑的是此异常对服务的/actuator/health 健康检测接口无法探测,即此接口状态返回UP,导致服务不会重启,但服务又无法接收新请求。
接下来查看节点的总线程数设置(未设置之前)。
Bash
# 宿主机上执行
# 内核级最大线程数,如果不文件不存在,则手动加一个
cat /proc/sys/kernel/threads-max
返回32768
# 最大PID值
cat /proc/sys/kernel/pid_max
返回32768
# 当前用户可创建的最大进程/线程数(nproc)
ulimit -u
返回32768
#查看最大线程数内核参数 通常 32768
sysctl kernel.pid_max
返回32768
cat /etc/security/limits.conf(设置之后的)

从以上几个指令查看结果来看确实是总线程数限制到了32000。
解决
用户可创建的最大线程数 = min (max user processes, threads-max, pid_max);
当然先止血,先调大宿主机节点的总线程数都拉到最大655350
Markdown
# 提升系统级线程数上限(当前 32768 可能不够)
sysctl -w kernel.threads-max=655350
sysctl -w kernel.pid_max=655350
# 持久化
echo "kernel.threads-max = 655350" >> /etc/sysctl.conf
echo "kernel.pid_max = 655350" >> /etc/sysctl.conf
sysctl -p
调整用户级 nproc 限制 /etc/security/limits.conf 追加
sql
root soft nofile 655350
root hard nofile 655350
* soft nofile 655350
* hard nofile 655350
调整系统进程数配置,在/etc/sysctl.conf添加最大进程和线程数量配置:
Java
kernel.pid_max=655350
kernel.threads-max=655350
执行sysctl -p加载并应用内核参数,执行sysctl -a |grep threads-max和sysctl -a |grep pid_max进行验证。
目前根据运维提供的资料将系统里面能改的参数都改了,但......将服务启动过了不久,仍然还有服务报无法创建新线程的异常。
至此开始怀疑是不是配置没生效,但从ulimit -a的一些指令来看都是没问题的,那就唯一一条路:重启大法。也许是需要将服务器重启才能生效。
于是建议将服务器进行了重启,结果总线程数终于能突破32000,至此配置生效。
当然 也要同时优化程序代码,从宿主机上统计应用时发现有多个java应用线程数达到4000以上甚至到了8000多,多个服务加一起总数肯定会超32000。