管理内核资源
管理内核资源¶
SeaboxSQL某些时候会耗尽操作系统的各种资源限制,当同一个系统上运行着多个拷贝的服务或在一个非常大的安装中时尤其如此。本节解释了SeaboxSQL使用的内核资源以及你可以采取的用于解决内核资源消耗相关问题的步骤。
共享内存和信号量¶
SeaboxSQL需要操作系统提供进程间通信(IPC)特性,特别是共享内存和信号量。Unix驱动的系统通常提供“System V” IPC、“POSIX” IPC,或者两者都有。
完全缺少这些功能通常表现为服务启动时的“Illegal system call”错误。这种情况下,除了重新配置内核之外别无选择。SeaboxSQL没有它们就不能工作。
在启动服务时,SeaboxSQL通常分配少量的System V共享内存,和大量的POSIX (mmap
)共享内存。另外, 在服务启动时会创建大量信号量,这些信号量可以是System V或POSIX风格。
目前,POSIX信号量用于Linux和FreeBSD系统,而其他平台则使用System V信号量。
System V IPC特性通常受系统范围分配限制的限制。
当SeaboxSQL超出了这些限制之一时,服务会拒绝启动并且并且留下一条有指导性的错误消息,其中描述了问题以及应该怎么做(又见服务启动失败)。相关的内核参数在不同系统之间的命名方式一致,表 System V IPC参数给出了一个概述。不过,设置它们的方法却多种多样。下面给出了对于某些平台的建议:
表 System V IPC参数
名称 | 描述 | 运行SeaboxSQL实例所需的值 |
---|---|---|
SHMMAX |
共享内存段的最大尺寸(字节) | 至少 1kB,但是默认值通常要高一些 |
SHMMIN |
共享内存段的最小尺寸(字节) | 1 |
SHMALL |
可用共享内存的总量(字节或页面) | 如果是字节,同SHMMAX ;如果是页面, 为ceil(SHMMAX/PAGE_SIZE) ,加上其他应用程序的空间 |
SHMSEG |
每个进程的最大共享内存段数目 | 只需要 1 段,但是默认值高很多 |
SHMMNI |
系统范围内的最大共享内存段数目 | 像SHMSEG 外加其他应用的空间 |
SEMMNI |
信号量标识符(即,集合)的最大数目 | 至少ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) 加上其他应用程序的空间 |
SEMMNS |
系统范围内的最大信号量数目 | ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5) / 16) * 17 外加其他应用的空间 |
SEMMSL |
每个集合中信号量的最大数目 | 至少 17 |
SEMMAP |
信号量映射中的项数 | 见文本 |
SEMVMX |
信号量的最大值 | 至少 1000 (默认值常常是 32767,如非必要不要更改) |
SeaboxSQL要求少量字节的 System V 共享内存(在 64位平台上通常是 48 字节) 用于每一个服务拷贝。在大多数现代操作系统上,这个量很容易得到。但是,如果你运行了很多个服务拷贝,或者其他应用也在使用 System V 共享内存,可能需要增加SHMALL
(系统范围内 System V共享内存的总量)。注意在很多系统上SHMALL
是以页面而不是字节来度量。
不太可能出问题的是共享内存段的最小尺寸(SHMMIN
),对SeaboxSQL来说应该最多大约是32字节(通常只是1)。而系统范围(SHMMNI
)或每个进程(SHMSEG
)的最大共享内存段数目不太可能会导致问题,除非你的系统把它们设成零。
当使用System V信号量时,SeaboxSQL对每个允许的连接(max_connections)、每个允许的自动清理工作者进程(autovacuum_max_workers)和每个允许的后台进程(max_worker_processes)使用一个信号量,以16个为一个集合。每个这种集合还包含第 17 个信号量,其中存储一个“magic number”,以检测和其它应用使用的信号量集合的冲突。 系统里的最大信号量数目是由SEMMNS
设置的,因此这个值必须至少和max_connections
加autovacuum_max_workers
再加max_worker_processes
一样大,并且每 16个连接外加工作者还要另外加一个(见表 System V IPC参数中的公式)。参数SEMMNI
决定系统中同一时刻可以存在的信号量集合的数目限制。因此这个参数必须至少为ceil((max_connections + autovacuum_max_workers + max_worker_processes + 5)/ 16)
。降低允许的连接数目是一种临时的绕开失败(来自函数semget
)的方法,通常使用让人混乱的措辞“No space left on device”。
在某些情况下可能还有必要增大SEMMAP
,使之至少与SEMMNS
相近。如果系统有这个参数(很多系统没有),这个参数定义信号量资源映射的尺寸,在其中每个连续的可用信号量块都需要一项。每当一个信号量集合被释放,那么它要么会被加入到该与被释放块相邻的一个现有项,或者它会被注册在一个新映射项中。如果映射被填满,被释放的信号量将丢失(直到重启)。因此信号量空间的碎片时间长了会导致可用的信号量比应有的信号量少。
与“semaphore undo”有关的其他各种设置,如SEMMNU
和SEMUME
不会影响SeaboxSQL。
当使用POSIX信号量时,所需的信号量数量与System V相同,即每个允许的连接(max_connections)、允许的自动清理工作进程(autovacuum_max_workers)和允许的后台进程(max_worker_processes)一个信号量。在首选此选项的平台上,POSIX信号量的数量没有特定的内核限制。
Linux系统中,默认的最大段尺寸是 32 MB,并且默认的最大总尺寸是 2097152 个页面。一个页面几乎总是 4096字节,除了在使用少见“huge pages”的内核配置中(使用getconf PAGE_SIZE
来验证)。
共享内存尺寸设置可以通过sysctl
接口来更改。例如,要允许 16 GB:
$ sysctl -w kernel.shmmax=17179869184
$ sysctl -w kernel.shmall=4194304
另外在重启之间这些设置可以被保存在文件/etc/sysctl.conf
中。我们强烈推荐这样做。
古老的发型可能没有sysctl
程序,但是可以通过操纵/proc
文件系统来得到等效的更改:
$ echo 17179869184 >/proc/sys/kernel/shmmax
$ echo 4194304 >/proc/sys/kernel/shmall
剩下的默认值都被设置得很宽大,并且通常不需要更改。
systemd RemoveIPC¶
如果正在使用systemd,则必须注意IPC资源(共享内存和信号量)不会被操作系统过早删除。从源代码安装SeaboxSQL时,这尤其值得关注。SeaboxSQL发布包的用户不太可能受到影响,因为seaboxs
用户通常是作为系统用户创建的。
控制当用户完全退出时是否移除IPC对象。系统用户免除。此设置在死板的systemd中默认为on,但某些操作系统分配默认为关闭。
当此设置打开时,典型的观察效果是SeaboxSQL服务使用的信号量对象在明显随机的时间被删除, 从而导致服务崩溃,并显示日志消息
LOG: semctl(1234567890, 0, IPC_RMID, ...) failed: Invalid argument
不同类型的IPC对象(共享内存与信号量,SystemV与POSIX)在systemd中略有不同,因此可能会发现某些IPC资源不会像其他IPC资源一样被删除。但依靠这些微妙的差异是不可取的。
“注销用户”可能会作为维护工作的一部分发生,或者当管理员以seaboxsql
用户或类似名称登录时手动发生,所以通常难以防止。
什么是“系统用户”是由/etc/login.defs
中的SYS_UID_MAX
设置在systemd编译时确定的。
打包和部署脚本应该小心,通过使用useradd -r
、 adduser --system
或等价物来创建seaboxsql
用户作为系统用户。
或者,如果用户帐户创建不正确或无法更改,建议设置
RemoveIPC=no
在/etc/systemd/logind.conf
或其他适当的配置文件中。
小心
至少要确保这两件事中的一件,否则SeaboxSQL服务将非常不可靠。
资源限制¶
Unix类操作系统强制了许多种资源限制,这些限制可能干扰你的SeaboxSQL服务的操作。尤其重要的是对每个用户的进程数目的限制、每个进程打开文件数目的限制以及每个进程可用的内存的限制。这些限制中每个都有一个“硬”限制和一个“软”限制。实际使用的是软限制,但用户可以自己修改成最大为硬限制的数目。而硬限制只能由root用户修改。系统调用setrlimit
负责设置这些参数。shell的内建命令ulimit
(Bourne shells)或limit
(csh)被用来从命令行控制资源限制。
内核也可以在某些资源上有系统范围的限制。在Linux上,/proc/sys/fs/file-max
决定内核可以支持打开的最大文件数。你可以通过往该文件写入一个不同的数值修改此值,或者通过在/etc/sysctl.conf
中增加一个赋值来修改。每个进程的最大打开文件数限制是在编译内核的时候固定的;更多信息请见/usr/src/linux/Documentation/proc.txt
。
SeaboxSQL服务为每个连接都使用一个进程,所以你应该至少和允许的连接同样多的进程,再加上系统其它部分所需要的进程数目。通常这个并不是什么问题,但如果你在一台机器上运行多个服务,资源使用可能就会紧张。
打开文件的出厂默认限制通常设置为“socially friendly”的值, 它允许许多用户在一台机器上共存,而不会导致不成比例的系统资源使用。如果你在一台机器上运行许多服务,这也许就是你想要的,但是在专门的服务上,你可能需要提高这个限制。
在另一方面,一些系统允许独立的进程打开非常多的文件;如果不止几个进程这么干,那系统范围的限制就很容易被超过。如果你发现这样的现像,并且不想修改系统范围的限制,你就可以设置SeaboxSQL的max_files_per_process配置参数来限制打开文件数的消耗。
内存过量使用¶
在 Linux 2.4及其后的版本中,默认的虚拟内存行为对SeaboxSQL不是最优的。由于内核实现内存过量使用的方法,如果SeaboxSQL或其它进程的内存要求导致系统用光虚拟内存,那么内核可能会终止SeaboxSQL的seaboxmaster 进程(主服务进程)。
如果发生了这样的事情,你会看到像下面这样的内核消息(参考你的系统文档和配置,看看在哪里能看到这样的消息):
Out of Memory: Killed process 12345 (seaboxs).
这表明seaboxs
进程因为内存压力而被终止了。尽管现有的数据库连接将继续正常运转,但是新的连接将无法被接受。要想恢复,SeaboxSQL应该被重启。
一种避免这个问题的方法是在一台你确信其它进程不会耗尽内存的机器上运行SeaboxSQL。如果内存资源紧张,增加操作系统的交换空间可以帮助避免这个问题,因为内存不足(OOM)机制(即终止进程这种行为)只有当物理内存和交换空间都被用尽时才会被调用。
如果SeaboxSQL本身是导致系统内存耗尽的原因,你可以通过改变你的配置来避免该问题。在某些情况中,降低内存相关的配置参数可能有所帮助,特别是shared_buffers
和work_mem
两个参数。在其他情况中,允许太多连接到数据库服务本身也可能导致该问题。在很多情况下,最好减小max_connections
并且转而利用外部连接池软件。
在 Linux 2.6及其后的版本中,可以修改内核的行为,这样它将不会“过量使用”内存。尽管此设置不会阻止OOM 机制被调用,但它可以显著地降低其可能性并且将因此得到更鲁棒的系统行为。这可以通过用sysctl
选择严格的过量使用模式来实现:
sysctl -w vm.overcommit_memory=2
或者在/etc/sysctl.conf
中放置一个等效的项。你可能还希望修改相关的设置vm.overcommit_ratio
。详细信息请参阅内核文档的https://www.kernel.org/doc/Documentation/vm/overcommit-accounting文件。
另一种方法,可以在改变或不改变vm.overcommit_memory
的情况下使用。它将 seaboxmaster 进程的进程相关的 OOM score adjustment 值设置为-1000
,从而保证它不会成为 OOM 机制的目标。 这样做最简单的方法是在 seaboxmaster的启动脚本中执行
echo -1000 > /proc/self/oom_score_adj
并且要在调用 seaboxmaster 之前执行。请注意这个动作必须以 root 完成,否则它将不会产生效果。所以一个被 root拥有的启动脚本是放置这个动作最容易的地方。如果这样做,你还应该在调用 seaboxmaster之前在启动脚本中设置这些环境变量:
export SD_OOM_ADJUST_FILE=/proc/self/oom_score_adj
export SD_OOM_ADJUST_VALUE=0
这些设置将导致 seaboxmaster 子进程使用普通的值为零的 OOM score adjustment 运行,所以 OOM机制仍能在需要时把它们作为目标。如果你想要子进程用某些其他 OOM score adjustment值运行,可以为SD_OOM_ADJUST_VALUE
使用其他的值(SD_OOM_ADJUST_VALUE
也能被省略,那时它会被默认为零)。如果你没有设置SD_OOM_ADJUST_FILE
,子进程将使用和seaboxmaster 相同的 OOM score adjustment 运行,这是不明智的,因为重点是确保 seaboxmaster具有优先的设置。
更老的Linux内核不提供/proc/self/oom_score_adj
,但是可能有一个具有相同功能的早期版本,它被称为/proc/self/oom_adj
。这种方式工作起来完全相同,除了禁用值是-17
而不是-1000
。
注意
有些厂商的 Linux 2.4 内核被报告有着 2.6 过量使用sysctl
参数的早期版本。不过,在没有相关代码的 2.4内核里设置vm.overcommit_memory
为 2将会让事情更糟。我们推荐你检查一下实际的内核源代码(见文件mm/mmap.c
中的vm_enough_memory
函数),验证一下这个是在你的内核中是被支持的,然后再在 2.4安装中使用它。文档文件overcommit-accounting
的存在不能当作是这个特性存在的证明。如果有疑问,请咨询一位内核专家或你的内核厂商。
透明大页¶
当SeaboxSQL使用大量连续的内存块时,使用大页会减少开销,特别是在使用大shared_buffers时。
要在SeaboxSQL中使用此特性,您需要一个包含CONFIG_HUGETLBFS=y
和CONFIG_HUGETLB_PAGE=y
的内核。
还必须调整内核设置vm.nr_hugepages
。要估计所需的巨大页的数量,请启动SeaboxSQL,而不启用巨大页,并使用/proc
文件系统来检查seaboxmaster的匿名共享内存段大小以及系统的大页大小。 这可能看起来像:
$ head -1 $SDDATA/seaboxmaster.pid
4170
$ pmap 4170 | awk '/rw-s/ && /zero/ {print $2}'
6490428K
$ grep ^Hugepagesize /proc/meminfo
Hugepagesize: 2048 kB
6490428
/ 2048
大约是3169.154
,因此在这个示例中你至少需要 3170
个大页,我们可以设置:
$ sysctl -w vm.nr_hugepages=3170
如果机器上的其他程序也需要大页,则更大的设置将是合适的。 不要忘记将此设置添加到/etc/sysctl.conf
,以便在重启后重新应用它。
有时候内核会无法立即分配想要数量的大页,所以可能有必要重复该命令或者重新启动。 (在重新启动之后,应立即将大部分机器的内存转换为大页。)要验证巨大的页面分配情况,请使用:
$ grep Huge /proc/meminfo
可能还需要赋予数据库服务的操作系统用户权限,让他能通过sysctl设置vm.hugetlb_shm_group
以使用大页, 和/或赋予使用ulimit -l
锁定内存的权限。
SeaboxSQL中大页的默认行为是尽可能使用它们并且在失败时转回到正常页面。要强制使用大页,可以在seaboxsql.conf
中把huge_pages设置成on
。注意此设置下如果没有足够的大页可用,SeaboxSQL将会启动失败。
Linux大页特性的详细描述可见https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.