哈喽大家好,我是咸鱼。

今天分享一个在压测过程中遇到的问题,当时排查这个问题费了我们好大的劲,所以我觉得有必要写一篇文章来记录一下。

问题出现

周末在进行压测的时候,测试和开发的同事反映压测有问题,请求打到 A 服务上被拒绝了。

我们登录服务器查看 A 服务的日志,发现频繁地报 Too many open files 错误,可以看到压测的时候该进程要处理大量的 socket,导致打开的文件描述符数量已经达到了操作系统允许的最大限制,因此无法再打开更多的文件。

java.io.IOException: Too many open files
...

既然是系统资源相关的问题,我们先 ulimit -n 看一下系统中进程能够使用的最大文件描述符是多少个:

[root@localhost ~]# ulimit -n
100000

为了稳妥起见,我们还查看了 /etc/security/limits.conf 文件的内容:

[root@localhost ~]# cat /etc/security/limits.conf
* soft nofile 100000
* hard nofile 100000

可以看到系统限制进程能够最多打开 100000 个文件(我们在服务器初始化的时候设置的值)。但是压测的量还没上去,A 服务上的进程打开文件数就超过了 10 万个吗?

查看一下这个进程打开了多少个文件:

[root@localhost ~]# cat /proc/<该进程的 PID>/fd | wc -l
8295

我们发现该进程才打开了八千多个文件,远远没有达到系统限制的 100000。

接着看下这个进程的文件描述符数量限制,通过 /proc/<Java 进程的 PID>/limits 文件来查看

[root@localhost ~]# cat /proc/<该进程的 PID>/limits
...
Max open files 8192 8192 files
...

奇怪,按理说每个进程的文件描述符使用限制应该是 100000,但是这里却显示只有 8192,说明系统层面的资源限制在这个进程上没有生效,而且这个 8192 是怎么来的,为什么是 8192 ?

我们重启了一下这个服务,发现重启之后该进程的资源限制生效了,Max open files 数量变成了 100000 !

# 重启服务
[root@localhost ~]# sh spring-boot.sh restart # 查看该进程的文件描述符数量限制
[root@localhost ~]# cat /proc/<该进程的 PID>/limits
...
Max open files 100000 100000 files
...

定位问题

发现了这个现象之后,我们接着排查了其他的服务,发现服务进程的 Max open files 数量都是 8192,而系统设置的却是 100000。

如果我们一旦手动重启服务,进程的 Max open files 数就变成了系统设置的 100000。

我们在初始化服务器的时候,已经修改了进程的最大打开文件数为 100000,如果配置没有生效,那也应该是系统的默认值 1024 ,而不是 8192。

就在一筹莫展的时候,我们注意到了一个细微差别:由于线上服务器较多,平时我们都是通过 Saltstack 来管理服务(包括服务的启动重启停止),而今天是在终端上重启服务的,所以会不会跟 Saltstack 相关?

然后我们为了验证执行了下面的步骤:

  1. 找到一台服务器,先查看了上面进程的最大打开文件数,发现是 8192。
  2. 手动重启一下服务,发现进程的最大打开文件数变成 100000
  3. 我们在 salt-master 上远程重启这台服务,发现进程的最大打开文件数变成了 8192。

接着我们在 salt-master 上远程执行 ulimit -a 命令

[root@salt-master ~]# salt <服务器 ip> cmd.run 'ulimit -a'
...
open files (-n) 8192
...

排查到这里,终于有点柳暗花明的感觉了,我们看一下这台服务器上 salt-minion 进程的资源限制:

[root@localhost ~]# cat /proc/<salt-minion 进程的 PID>/limits
...
Max open files 8192 8192 files
...

又因为 salt-minion 是通过 systemctl 来管理的,所以我们在这台服务器上查看 salt-minion 的服务注册文件:

[root@localhost ~]# cat /usr/lib/systemd/system/salt-minion.service
[Unit]
... [Service]
KillMode=process
Type=notify
NotifyAccess=all
LimitNOFILE=8192
ExecStart=/usr/bin/salt-minion [Install]
...

果然,奇怪的 8192 出现在了这两处地方!

关于 Linux 下 Ulimit 资源限制

首先,/etc/security/limits.conf 文件中的配置对于通过 PAM 认证登录的用户资源限制是有效的。

也就是说,登陆了系统的用户,无论是交互式登录还是非交互式登录,其资源限制都会受到 limits.conf 中的配置影响。

但是,在 CentOS 7/RHEL 7 等系统中,默认采用 Systemd 作为 init 系统,取代了之前的 SysV init,对于 Systemd 启动的服务(例如使用 systemctl 启动的服务),limits.conf 中的配置对其资源限制是不生效的。

这是因为 Systemd 会忽略 limits.conf 中的设置,而是使用自己的资源管理机制。

这里补充一下,在 CenOS 5/6 中,/etc/security/limits.conf/etc/security/limits.d 中的配置文件是为通过PAM登录的用户设置资源限制的。这些限制在用户登录时由PAM模块加载并应用(什么是 PAM ,你可以简单理解为一般情况登陆了终端都会加载 PAM 模块),因此仅在用户会话期间生效。



所以就会出现某进程在机器重启后资源限制设置与 /etc/security/limits.conflimits.d 下的文件不一致的问题,可能是因为进程是在系统启动时自动启动的,而不是通过用户登录而启动的。因此不会受到 PAM 模块加载的影响。在这种情况下,进程的资源限制可能受到系统级别的默认限制或其他配置文件的影响。

我们对某一台 CentOS 6 的机器进行重启后,发现上面设置了开机自启动的进程的资源限制都发生了变化(变成了系统设置的默认值),一旦我们手动重启,资源限制则设置成了跟 /etc/security/limits.conf 文件设置的一致

对于一些设置了开机自启动的进程,如果在机器重启后保持资源限制不发生变化,可以在进程的启动脚本里加上关于资源限制设置的命令,比如说 ulimit -SHn 10000

所以在 Systemd 中,可以通过在服务单元文件中设置 Limit* 选项来控制服务的资源限制,比如限制进程的最大打开文件数 LimitNOFILE 为 8192。

LimitNOFILE=8192

当我们通过 Salt-master 来管理远程服务器的时候(服务器上面往往部署了 Salt-minion),即 Salt-master 发送命令给 Salt-minion 时,通常情况下,Salt-minion 会直接在自身进程中执行相应的操作。

如果是通过 Salt-minion 来启动一个进程,这个进程则会继承 Salt-minion 的资源限制配置。

这也就是为什么通过 salt-minion 管理的进程的最大打开文件数都是 8192,因为 salt-minion 的最大打开文件数就是 8192。

解决问题

既然知道了这是关于 systemd services 的资源限制相关的问题,那就好解决了。

  • 针对所有的 service :

配置 systemd services 的资源限制可以在全局范围内进行。这些配置文件分别位于 /etc/systemd/system.conf/etc/systemd/user.conf

system.conf 文件适用于系统级实例,而 user.conf 文件适用于用户级实例。一般建议在 system.conf 中配置服务的资源限制,但如果在 /etc/systemd/system.conf 文件中修改配置,则需要重启系统才能使更改生效。

此外,还可以通过在 /etc/systemd/system.conf.d//etc/systemd/user.conf.d/ 目录中放置 .conf 文件进行配置。

需要注意的是,system.conf.d/*.conf 中的配置会覆盖 system.conf 中的配置。

如果你打算修改所有通过 systemctl 管理的服务进程的资源限制(比如修改最大文件打开数量)

那可以修改/etc/systemd/system.conf

[root@localhost ~]# vim /etc/systemd/system.conf
DefaultLimitNOFILE=100000
  • 针对单个 service:

这次案例的解决方法就是要修改单个 service (即 salt-minion)的资源限制配置。

# 修改 salt-minion 的 service 文件,改成和系统一样的资源限制配置
[root@localhost ~]# cat /usr/lib/systemd/system/salt-minion.service
...
[Service]
LimitNOFILE=100000
...

修改完之后别忘了重启。

[root@localhost ~]# systemctl daemon-reload

[root@localhost ~]# systemctl restart salt-minion.service

Saltstack 最大打开文件数问题之奇怪的 8192的更多相关文章

  1. linux 打开文件数 too many open files 解决方法

    linux 打开文件数 too many open files 解决方法 too many open files 出现这句提示的原因是程序打开的文件/socket连接数量超过系统设定值. 查看每个用户 ...

  2. 在Linux最大打开文件数限制下 MySQL 对参数的调整

    http://www.actionsky.com/docs/archives/78  2016年4月7日  周文雅 目录 1 起因 2 说明 3 MySQL调整参数的方式 3.1 计算 request ...

  3. 放开Linux内核对用户进程可打开文件数和TCP连接的限制

    一. 检查linux内核uname -alsb_release -a 二. 用户进程可打开文件数限制1) vim /etc/security/limits.conf*       -      nof ...

  4. centos7,进程最大打开文件数 too many open files错误

    遇到一问题,tomcat最近发生几次异常,查看日志,发现一直报 too many open files,熟悉的同学都知道这是用户打开文件数过多导致的, 再用命令ls /proc/20861/fd/ | ...

  5. 遇到问题----linux-----linux 打开文件数 too many open files 解决方法

    在运行某些命令或者 tomcat等服务器持续运行 一段时间后可能遇到   too many open files. 出现这句提示的原因是程序打开的文件/socket连接数量超过系统设定值. 查看每个用 ...

  6. 调整Linux最大打开文件数

    #!/bin/bash ## 文件数限制 ulimit -n ulimit -Sn ulimit -Hn ## fs.nr_open,进程级别 ## fs.file-max,系统级别 ## 最大文件描 ...

  7. mysql打开文件数太多的解决办法

    http://www.orczhou.com/index.php/2010/10/mysql-open-file-limit/ http://www.cnblogs.com/end/archive/2 ...

  8. linux打开文件数测试

    /proc/sys/kernel/threads-max 系统最大线程数量 /proc/sys/vm/max_map_count 限制一个进程可以拥有的VMA(虚拟内存区域)的数量 /proc/sys ...

  9. the max number of open files 最大打开文件数 ulimit -n RabbitMQ调优

    Installing on RPM-based Linux (RHEL, CentOS, Fedora, openSUSE) — RabbitMQ https://www.rabbitmq.com/i ...

  10. Linux 打开文件数

    linux设置最大打开文件数 - daiyudong2020的博客 - CSDN博客 https://blog.csdn.net/daiyudong2020/article/details/77828 ...

随机推荐

  1. 到什么程度才叫精通 Linux?

    大家好,我是陶朱公Boy,一个认真生活,总想超越自己的程序员. 前言 知乎上有一个提问:到什么程度才叫精通 Linux?                              ↓↓↓ 今天,我们就 ...

  2. JS Leetcode 530. 二叉搜索树的最小绝对差 题解分析,再次了解中序遍历

    壹 ❀ 引 本题来自LeetCode 783. 二叉搜索树节点最小距离,题目描述如下: 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 . 示例 1: 输入:root ...

  3. NC207569 牛牛爱奇数

    题目链接 题目 题目描述 在牛牛面前放着 \(n\) 个数,这些数字既有奇数也有偶数,只不过牛牛对奇数情有独钟,他特别想让这些数都变成奇数. 现在牛牛获得了一种能力,他可以执行一种操作:每次选中一个偶 ...

  4. Git 分支与合并

    1.  Git 对象 Git 的核心部分是一个简单的键值对数据库.可以向 Git 仓库中插入任意类型的内容,它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容. 所有内容均以树对象和数据对象的 ...

  5. Swift —— 一、架构解析

    一.简介 OpenStack 对象存储 (swift) 用于冗余.可扩展的数据 使用标准化服务器集群存储PB的存储 可访问的数据.它是一种长期存储系统,可存储大量 可以检索和更新的静态数据.对象存储使 ...

  6. Jenkins共享库使用

    简单使用 共享库(Shared libraries)是一种可以用来封装函数.变量甚至整个 Pipeline 的机制.通过共享库,可以将常用的功能和流程逻辑定义在单独的 Groovy 脚本中,然后在多个 ...

  7. yolov5项目cuda错误解决

    CUDA报错解决 # 报错详情 AssertionError: CUDA unavailable, invalid device 0 requested 查看cuda版本 先看一下电脑是否支持GPU, ...

  8. 【C# .Net】继承重写父类方法,C# 与 JAVA的不同之处

    一直都没仔细研究c#重写,new关键字的作用,最近在回头看书,复习C#基础的时候才发现了 C# 重写和 JAVA大不一样的地方. C# 提供特定实现的子类可以重写(override)标识为 virtu ...

  9. ASP.NET 上传文件导入Excel

    前言 本文对应的场景是导入Excel数据,Excel对应的字段都配置在xml文件中.截图如下: 代码实战 工具类 实体类:XMLReadModel.cs public class XMLReadMod ...

  10. 【ACM专项练习#02】整行字符串、输入vector、打印图形、处理n组数据以及链表操作等

    输入整行字符串 平均绩点 题目描述 每门课的成绩分为A.B.C.D.F五个等级,为了计算平均绩点,规定A.B.C.D.F分别代表4分.3分.2分.1分.0分. 输入 有多组测试样例.每组输入数据占一行 ...