对于数据库系统这样的基础软件,许多小伙伴都有体会,就是参数调优是十分“玄学”的一件事。本文我们就将针对 SequoiaDB 的内存和操作系统调优的最佳实践进行介绍,希望可以帮助大家处理一些遇到的常见问题。
常见问题:“-10”
Failed to create new agent: boost::thread_resource_error: Resource temporaily unavailable Failed to create new agent, probe = 30 Failed to create subagent thread, rc = -10 Failed to start session EDU, rc = -10h
Linux 操作系统 create thread 受到什么限制
那么 Linux 操作系统在 create thread 时,主要受到文件句柄数和内存分配两个重要资源的限制。
Linux 文件句柄
在 Linux 操作系统中,号称一切皆为文件,无论是进程、线程、socket 还是其他,最终都会被操作系统归为文件操作。操作系统或者进程,每申请一个资源,例如:线程、socket,都会打开一个文件,当这个文件处于打开状态时,就认为 Linux 系统打开了一个文件句柄。那么Linux 的文件句柄数限制又是什么呢?其实这个限制就是操作系统,或者是某个用户,或者某个进程所能够打开的最多文件的数量的限制。读者们有了这个概念后,让作者继续介绍Linux 操作系统是如何对文件句柄数进行限制的。
Linux 操作系统最大句柄数
另外,关于句柄数的限制,还不单单是进程中和一个用户的句柄数限制,还有整个操作系统的句柄数限制,因为一个操作系统,总不能无限地打开句柄的。所以又引入另外一个设置,操作系统最大打开的句柄数限制。Linux 操作系统有一个最大打开句柄数的限制,以 centos 7 系统为例,该参数是被保存在 /proc/sys/fs/file-max 文件中。用户可以通过以下命令,查看 Linux 当前总打开的句柄数。
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|awk '{print $1}' | awk '{sum += $1};END {print sum}'
如果 Linux 最大句柄数设置得过小,容易导致 Linux 系统在处理复杂操作时,发生很多莫名其妙的问题。如果用户希望临时修改 Linux 最大句柄数,可以直接在 root 用户下执行:
echo MAX-FILE-NUM > /proc/sys/fs/file-max
如果用户希望永久修改 Linux 最大句柄数,可以编辑 /etc/sysctl.conf 文件,增加 fs.file-max = MAX-FILE-NUM 内容,然后在 root 用户下执行:
sysctl -p
用户最大进程数
一个操作系统用户,也有它最大启动的进程数,查看方式为:
ulimit -a
用户可以通过 max user processes 项获取当前用户所能启动的最大进程数。该参数的官方解释如下:
Linux itself has a Max Processes per user limit. This feature allows us to control the number of processes an existing user on the server may be authorized to have
虽然该参数是一个系统用户的进程数限制,但是从使用效果分析,对线程数也有明显限制效果,毕竟线程是从进程中派生出来的资源。如果用户希望临时修改 max user processes 参数,可以直接通过以下命令进行设置:
ulimit -u MAX-USER-PROCESSES-NUM
如果希望永久设置 max user processes 参数,可以使用系统 root 用户编辑/etc/security/limits.conf 配置文件,增加以下内容进行设置:
<domain> <type> <item> <value> * soft nproc unlimited * hard nproc unlimited
Note: max user processes 参数允许设置为 unlimited。
进程最大句柄数
在 Linux 系统中,一个进程所能够拥有的最大句柄数,查看方式为:
ulimit -a
用户可以通过 open files 项获取当前用户对每个进程最大句柄数的限制。如果用户希望临时修改系统用户的 open files 参数,可以直接通过以下命令进行设置:
ulimit -n OPEN-FILES-NUM
如果希望永久设置,可以使用系统 root 用户编辑 /etc/security/limits.conf 配置文件,增加以下内容进行设置:
<domain> <type> <item> <value> * soft nofile 65536 * hard nofile 65536
这里有一个小细节需要读者们注意的。假如,系统 root 用户的 ulimit open file 设置为 1024,则该系统的其他用户无法将 ulimit open file 设置得比 1024大。所以如果用户希望调大普通用户的 ulimit open file 值,则需要首先确认系统 root 用户的 ulimti open file 值。
NOTE: 谨记 open files 参数不能够被设置为 unlimited,一般设置为 65535 即可。
Linux 内存分配
在Linux 操作系统中,内存管理是一个细致活。其实在Linux 的系统内存管理中,有两层管理,分别是物理内存和虚拟内存。
物理内存
操作系统的物理内存读者们很好理解,就是硬件服务器配置的RAM 大小,也是人们日常所说的服务器内存大小。用户可以通过以下命令查看服务器的物理内存大小:
free -m
例如 free 命令执行结果如下:
total used free shared buffers cached Mem: 3874 1773 2100 0 201 576 -/+ buffers/cache: 996 2878 Swap: 2044 0 2044
该环境的物理内存就是 3874 MB。
虚拟内存
Linux 系统的虚拟内存,是操作系统为了更好管理物理内存而设计出来的一层虚拟资源。因为操作系统在运行过程中,各个进程都在使用、释放物理内存,必然造成系统空闲的物理内存是不连续的。
操作系统为了使程序申请系统内存更加方便和友好,专门为物理内存资源构造了一层虚拟内存地址,使得程序可以使用连续的内存地址进行程序开发、运行,而忽略物理内存地址的不连续问题。
所以程序或是进程在向操作系统 malloc 一段连续的内存时,实际从虚拟内存中申请了一段连续的地址。在操作系统的内存映射表中,记录了虚拟内存地址指向真实的物理内存地址。
同时,读者们要注意,即使进程 malloc 了一段内存资源,但实际上在进程 malloc 内存后,并不会真的马上对物理内存资源进行标记,只有当真正开始写入数据时,才会实际标记、使用真实的物理内存。
创建线程所需内存
当进程向操作系统申请创建线程时,操作系统需要预先分配多少内存给这个线程呢?在Linux 操作系统中,一个进程创建一个线程,会自动分配固定大小的内存给这个新线程,该内存大小由 ulimitstack size 定义。用户可以通过以下命令查看:
ulimit -a
用户可以通过 stack size 项了解每个新建线程被分配了多少内存。默认情况下,stack size 项为 8192(8MB)。如果用户希望临时修改 stack size 参数,可以直接通过以下命令进行设置
ulimit -s STACK-SIZE-NUM
如果希望永久设置 stack size 参数,可以使用系统 root 用户编辑/etc/security/limits.conf 配置文件,增加以下内容进行设置:
<domain> <type> <item> <value> * soft stack 8192 * hard stack 8192
Linux 允许 malloc 的最大内存
前面向读者们介绍了 Linux 内存资源,实际上是分为物理内存和虚拟内存,而一个操作系统最大能够 malloc 多少内存呢?这个参数被记录在 /proc/meminfo 文件中,用户可以通过以下命令获得 Linux 最大允许 malloc 的内存大小和已经被 malloc 了的内存大小:
cat /proc/meminfo | grep Commit
该命令将打印两个重要的数值;
CommitLimit
Committed_AS
CommitLimit 参数,是操作系统最大可以 malloc 的内存的大小。Committed_AS 参数,是操作系统当前已经被 malloc 了的内存的大小。所以简单的总结,就是当 Committed_AS 参数的值无限接近 CommitLimit 参数的值时,证明当前的操作系统,真的没有太多可用内存可以继续给 malloc 了。
CommitLimit 如何计算
在Linux 的/proc/meminfo 文件中,CommitLimit 参数的大小,实际上和 3 个Linux 内核参数有关系,分别是:
0,表示内核将检查是否有足够的可用内存供应用进程使用,如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程;
1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何;
2,表示内核允许分配超过所有物理内存和交换空间总和的内存
/proc/sys/vm/overcommit_ratio 参数,默认值为50,只有当 /proc/sys/vm/overcommit_memory = 2 时才会生效,表示可以被使用的最大物理内存比例。Swap 空间的大小,就是操作系统被设置的交换空间的大小。
关于线程创建内存资源限制小结
通过前面关于内存知识点的介绍,如果一个进程需要 create thread,首先需要根据 ulimit stack size 申请一段虚拟内存地址。
如果 Linux 的/proc/meminfo 文件中 Committed_AS 值已经无限逼近 CommitLimit 值时,则证明 Linux 已经无法再申请新的虚拟内存地址了。
前面关于物理内存和虚拟内存的部分也介绍到,如果进程只是 malloc 内存,而不真实利用这些内存保存数据,实际上是不会使用物理内存的。换言之,此时用户通过 free 命令查看空闲内存,会发现内存充足,进程却无法malloc 新内存了的怪现象。同理,进程也无法创建新的线程了。
所以 Linux 系统在 create thread 失败时,根本原因不是物理内存不足,而是操作系统无法继续 malloc 内存了。这两者实际含义完全不同,读者们需要区分清楚。
“-10” 错误解决
设置 ulimit -n 参数,设置为 65535
设置 ulimit -u 参数,设置为 unlimited
设置 ulmit -s 参数,可以考虑适当调小一点,例如设置成 4096 或者 2048
设置 /proc/sys/vm/overcommit_memory 参数,将其设置为 2
设置 /proc/sys/vm/overcommit_ratio 参数,适当调大一点,但是建议不要设置超过 90
为系统配置适当大小的 Swap 交换空间