博客 > 巨杉Tech | 常见问题参数调优实践(一)

巨杉Tech | 常见问题参数调优实践(一)

 2019-11-09  SequoiaDB,技术教程
SequoiaDB 巨杉数据库,作为一款面向 OLTP 的分布式数据库,被广泛使用于海量数据高并发操作场景中。

对于数据库系统这样的基础软件,许多小伙伴都有体会,就是参数调优是十分“玄学”的一件事。本文我们就将针对 SequoiaDB 的内存和操作系统调优的最佳实践进行介绍,希望可以帮助大家处理一些遇到的常见问题。


常见问题:“-10”

在一些复杂的数据处理场景中,有时应用或者数据库节点会报告 "-10" 错误。通过官方信息中心(http://doc.sequoiadb.com/cn/sequoiadb-cat_id-1432190985-edition_id-0),用户可以了解到 "-10" 错误,定义为“系统错误”。这是一个非常笼统的说明,会让很多 SequoiaDB 巨杉数据库的使用者感到无所适从,以至于不知道从哪里入手去解决该问题。

接下来,我们就将全面地向各位读者介绍 "-10”错误产生的现象,以及它背后所包含的技术原理,希望能够让读者再次遇到 “-10” 错误时,能够从容地排查问题和正确地解决问题。

“-10” 错误,通常发生在持续高并发地对 SequoiaDB 数据库进行数据操作时发生。如果使用 Spark SQL 对 SequoiaDB 数据库进行大规模并行数据计算时,也可能会出现 “-10” 错误。当应用程序从 SequoiaDB 数据库中收到 “-10” 错误时,通过数据库的 diaglog 日志,会发现如下关键信息。
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 内核参数有关系,分别是:

1. /proc/sys/vm/overcommit_memory
2. /proc/sys/vm/overcommit_ratio
3. Swap 空间大小
/proc/sys/vm/overcommit_memory 参数是Linux 对内存管理中非常重要的参数,默认值为:0。 它可以取值 0, 1,2,分别的含义是:
  • 0,表示内核将检查是否有足够的可用内存供应用进程使用,如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程;

  • 1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何;

  • 2,表示内核允许分配超过所有物理内存和交换空间总和的内存

/proc/sys/vm/overcommit_ratio 参数,默认值为50,只有当 /proc/sys/vm/overcommit_memory = 2 时才会生效,表示可以被使用的最大物理内存比例。Swap 空间的大小,就是操作系统被设置的交换空间的大小。

当 /proc/sys/vm/overcommit_memory = 2 时,CommitLimit 参数值的计算公式为:CommitLimit = Swap + 物理内存 * (/proc/sys/vm/overcommit_ratio / 100)。

  • 关于线程创建内存资源限制小结

通过前面关于内存知识点的介绍,如果一个进程需要 create thread,首先需要根据 ulimit stack size 申请一段虚拟内存地址。

如果 Linux 的/proc/meminfo 文件中 Committed_AS 值已经无限逼近 CommitLimit 值时,则证明 Linux 已经无法再申请新的虚拟内存地址了。

前面关于物理内存和虚拟内存的部分也介绍到,如果进程只是 malloc 内存,而不真实利用这些内存保存数据,实际上是不会使用物理内存的。换言之,此时用户通过 free 命令查看空闲内存,会发现内存充足,进程却无法malloc 新内存了的怪现象。同理,进程也无法创建新的线程了。

所以 Linux 系统在 create thread 失败时,根本原因不是物理内存不足,而是操作系统无法继续 malloc 内存了。这两者实际含义完全不同,读者们需要区分清楚。


“-10” 错误解决

所以,当用户真的在使用 SequoiaDB 数据库过程中,遇到了 "-10" 错误,首先莫慌,深呼吸 1 分钟稳定一下情绪,然后开始仔细查看SequoiaDB 各个节点的diaglog 日志,根据 coord 节点 -> datanode 节点的顺序,排查是哪个节点抛出 "-10" 错误,然后遵循以下原则进行系统参数优化:


  • 设置 ulimit -n 参数,设置为 65535

  • 设置 ulimit -u 参数,设置为 unlimited

  • 设置 ulmit -s 参数,可以考虑适当调小一点,例如设置成 4096 或者 2048

  • 设置 /proc/sys/vm/overcommit_memory 参数,将其设置为 2

  • 设置 /proc/sys/vm/overcommit_ratio 参数,适当调大一点,但是建议不要设置超过 90

  • 为系统配置适当大小的 Swap 交换空间


后记

针对类似本文阐述的“玄学”解决问题,相信大家也会在使用各种产品软件时候遇到不少。巨杉数据库也会持续在新版本中优化和解决大家常见的一些诉求,另外,我们版本的运维和监控工具很快也会和大家见面!有了新工具,相信我们的用户们会更轻松简单的解决数据库的性能调优问题,请大家多多关注~



准备开始体验 SequoiaDB 巨杉数据库?