1.问题背景mysql
对于分布式数据库和分布式环境,高并发和高性能压力的状况下,出现线程建立失败等等问题也是十分常见的,这时候就十分考虑数据库管理员的经验,须要能快速的定位到问题和瓶颈所在,快速解决。本文也是做为一个最佳实践,告诉你们如何在高并发状况下定位问题,排除问题,解决瓶颈。linux
2.问题定位程序员
SequoiaDB在集群环境中的 -10 错误码,在认真查阅节点的 diaglog 日志后,发现是操做系统 create thread 失败的问题。sql
如咱们的测试环境下,SequoiaDB节点的 diaglog 的错误日志信息数据库
阅读这个错误日志的内容,经过看到相似以下的关键信息centos
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 = -10服务器
那么通常操做系统在建立线程时,会受限于哪些参数呢,主要有几个:文件句柄数限制、操做系统句柄数限制和内存资源。session
1)文件句柄数多线程
在linux 操做系统中,号称一切皆为文件,无论是进程、线程、socker 仍是其余,最终都会被操做系统归为文件操做。操做系统或者进程,每申请一个资源,例如线程、socker,都会打开一个文件,那么这个文件打开状态,就能够简单理解为文件句柄。其中,“句柄数限制“表明操做系统或者某个进程所可以打开的最多文件的数量的限制。并发
你们有了这个概念后,咱们再来看操做系统是如何对文件句柄数进行限制的。在操做系统中,有一个神奇的命令 - ulimit 这一个命令能够设置许多限制值,进程文件句柄数就是其中之一。
例如咱们能够查看 root 用户的 ulimit 输出, -n open file = 1024 就是root 用户容许进程打开的最大文件句柄数。
此处咱们须要注意,因为root 用户是Linux 中的管理员用户,因此若是root 用户的 ulimit open file 设置成 1024, 那么其余的用户,例如test、mysql 用户等,想将 ulimit opon file 设置成 大于 1024,是不行的。
所以,普通用户的 ulimit 值修改前,必需要注意root用户的ulimit值,保证普通用户的ulimit值比root用户的设置值小。
2)操做系统句柄数
除了进程中的句柄数限制,整个操做系统的句柄数限制一样会对数据库运行产生影响。在句柄数限制下,由于一个操做系统,总不能无限地打开句柄的。因此又引入另一个设置,操做系统最大打开的句柄数限制。
这个值在 centos 7 中,是被保存在 /proc/sys/fs/file-max 文件中。
若是操做系统总的句柄数已经达到上限,那么即便进程尚未启动几个线程,也会出现句柄不够的状况。
若是但愿临时修改操做系统最大句柄数的设置,能够直接执行,便可: echo 2000000 > /proc/sys/fs/file-max
若是但愿永久修改操做系统最大句柄数的设置,能够编辑 /etc/sysctl.conf 文件,增长 fs.file-max = 2000000 内容,而后在root 用户中执行 sysctl -p 便可。
3)内存资源
针对内存资源的优化,在建立线程时,在Linux 中,是须要给它预先分配内存的 – 也叫 栈大小,用来存储线程中数据的值。
咱们程序员都知道,内存主要分为两个大的部分,一个称为 “堆”,一个称为“栈”。在程序中,“堆”一般是程序用来保存常量和变量名字的,“栈”则一般是程序来用保存具体的变量数字的。
此前咱们说到,若是系统内存不足,也是没法建立线程的。这个缘由就是在于建立线程时,操做系统须要分配一块内存给线程,这个内存是多大呢,就是 ulimit 中 -s stack size 的大小。若是操做系统连 stack size 大小的内容都没法拿出来了,建立线程就会失败。
整个服务器资源,为何这么一点内存都没有了?
其实若是仔细查看操做系统,你就会发现,那么多进程,每一个进程又是那么多线程在运行,每一个线程都在申请内存(注意,这块的内存是物理内存),内存不足正常的很。这个也容易让人联想到JVM 的OOM ,可是他们真的不是一回事,你们千万不要误会。
要解决这个问题也比较简单 – 直接粗暴?就是将 ulimit 中 -s stack size 调小一点,每一个线程不要申请那么多内存了,操做系统的内存资源就会更加的充裕。毕竟程序、线程这些,都是用完就完了,不可能都永久占用内存的。
3.其余须要注意的点
除了上述解决方案,仍没法解决建立线程失败的额问题
执行 ulimit -a 命令,参数看起来也正常,可是系统是不是完成了设置?咱们须要真正确认SequoiaDB进程的ulimit 参数是啥。
确认的方式有两种:
4.备注:关于句柄数和线程的命令
查看 某个进程总共开启了多少个 线程,能够
cat /proc/$PID/status | grep Threads
pstree -p $PID ,而后+1,因为还有主进程
top -Hp $PID,而后查看头部 “Threads”参数
ps hH p $PID | wc -l
查看linux 目前总打开的句柄数
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr|awk '{print $1}' | awk '{sum += $1};END {print sum}'
查看某个进程打开的总句柄数
lsof -n|awk '{print $2}'|sort|uniq -c|sort -nr | grep $PID