在 Linux 中为 PostgreSQL 设置内存不足杀手

在 Linux 中为 PostgreSQL 设置内存不足杀手

当Linux中数据库服务器意外退出时,需要查找原因。 可能有几个原因。 例如, 信号发生器 — 由于后端服务器中的错误而失败。 但这种情况很少见。 大多数情况下,您只是耗尽了磁盘空间或内存。 如果磁盘空间不足,只有一种方法:释放空间并重新启动数据库。

内存不足杀手

当服务器或进程耗尽内存时,Linux 提供两种解决方案:使整个系统崩溃或终止消耗内存的进程(应用程序)。 当然,最好终止该进程并避免操作系统崩溃。 简而言之,Out-Of-Memory Killer 是一个杀死应用程序以防止内核崩溃的进程。 它牺牲了应用程序来保持操作系统的运行。 我们先讨论OOM是如何工作的以及如何控制它,然后看看OOM Killer如何决定终止哪个应用程序。

Linux 的主要任务之一是在进程请求时为其分配内存。 通常,进程或应用程序会向操作系统请求内存,但不会完全使用它。 如果操作系统将内存分配给每个需要内存但不打算使用它的人,那么内存很快就会耗尽,系统就会失败。 为了避免这种情况,操作系统为进程保留内存,但实际上并不释放它。 仅当进程实际要使用内存时才分配内存。 碰巧操作系统没有空闲内存,但它为进程分配内存,当进程需要内存时,操作系统会在可以的情况下分配内存。 缺点是有时操作系统会保留内存,但在适当的时候没有可用内存,系统就会崩溃。 OOM 在这种情况下发挥着重要作用,它会终止进程以防止内核发生恐慌。 当 PostgreSQL 进程被迫终止时,日志中会出现一条消息:

Out of Memory: Killed process 12345 (postgres).

如果系统内存不足且无法释放,则调用该函数 out_of_memory。 在这个阶段,她只剩下一件事要做——完成一个或多个流程。 OOM-killer 应该立即终止进程还是可以等待? 显然,当out_of_memory被调用时,是由于等待I/O操作或分页到磁盘。 因此,OOM Killer 必须首先执行检查,并根据检查结果决定需要终止该进程。 如果以下所有检查都是肯定的,OOM 将终止该过程。

工艺选择

当内存耗尽时,调用该函数 out_of_memory()。 它有一个功能 select_bad_process(),它接收来自函数的评估 badness()。 “最差”的流程将成为目标。 功能 badness() 根据一定的规则选择进程。

  1. 内核本身需要一些最小内存。
  2. 您需要释放大量内存。
  3. 无需终止使用少量内存的进程。
  4. 需要完成最少的流程。
  5. 复杂的算法增加了用户自己想要完成的那些过程的完成机会。

完成所有这些检查后,OOM 检查分数 (oom_score)。 OOM 分配 oom_score 每个进程,然后将该值乘以内存量。 具有较大值的进程更有可能成为 OOM Killer 的受害者。 与 root 用户关联的进程得分较低,并且不太可能被强制终止。

postgres=# SELECT pg_backend_pid();
pg_backend_pid 
----------------
    3813
(1 row)

Postgres 进程 ID 为 3813,因此在另一个 shell 中可以使用此内核参数获取分数 oom_score:

vagrant@vagrant:~$ sudo cat /proc/3813/oom_score
2

如果您根本不希望 OOM-Killer 终止进程,还有另一个内核选项: oom_score_adj。 添加较大的负值可减少完成您重视的流程的机会。

sudo echo -100 > /proc/3813/oom_score_adj

设置一个值 oom_score_adj,在服务块中设置 OOMScoreAdjust:

[Service]
OOMScoreAdjust=-1000

或者使用 oomprotect 在一个团队中 rcctl.

rcctl set <i>servicename</i> oomprotect -1000

强制终止进程

当一个或多个进程已被选择时,OOM-Killer 会调用该函数 oom_kill_task()。 该函数向进程发送终止信号。 如果内存不足 oom_kill() 调用此函数向进程发送 SIGKILL 信号。 一条消息被写入内核日志。

Out of Memory: Killed process [pid] [name].

如何控制 OOM-Killer

在 Linux 上,您可以启用或禁用 OOM-Killer(尽管不建议使用后者)。 要启用或禁用,请使用参数 vm.oom-kill。 要在运行时启用 OOM-Killer,请运行命令 sysctl.

sudo -s sysctl -w vm.oom-kill = 1

要禁用 OOM-Killer,请在同一命令中指定值 0:

sudo -s sysctl -w vm.oom-kill = 0

该命令的结果不会永久保存,只会保存到第一次重新启动之前。 如果您需要更多持久性,请将此行添加到文件中 /etc/sysctl.conf:

echo vm.oom-kill = 1 >>/etc/sysctl.conf

启用和禁用的另一种方法是写入变量 panic_on_oom。 该值始终可以签入 /proc.

$ cat /proc/sys/vm/panic_on_oom
0

如果将该值设置为0,那么当内存耗尽时,不会出现内核恐慌。

$ echo 0 > /proc/sys/vm/panic_on_oom

如果将该值设置为1,那么当内存耗尽时,将会发生内核恐慌。

echo 1 > /proc/sys/vm/panic_on_oom

OOM-Killer 不仅可以打开和关闭。 我们已经说过,Linux 可以为进程保留比可用内存更多的内存,而无需实际分配内存,并且此行为由 Linux 内核参数控制。 该变量负责此操作 vm.overcommit_memory.

您可以为其指定以下值:

0: 内核自行决定是否保留过多的内存。 这是大多数 Linux 版本的默认设置。
1: 内核总是会保留额外的内存。 这是有风险的,因为内存可能会耗尽,因为很可能有一天进程会需要它。
2: 内核不会保留比参数中指定的更多的内存 overcommit_ratio.

使用此参数,您可以指定允许过度保留的内存百分比。 如果没有空间,则不会分配内存,并且保留将被拒绝。 这是为 PostgreSQL 推荐的最安全的选项。 OOM-Killer 受到另一个因素的影响——交换能力,该能力由变量控制 cat /proc/sys/vm/swappiness。 这些值告诉内核如何处理分页。 该值越高,OOM 终止进程的可能性越小,但由于 I/O 操作,它确实会对数据库产生负面影响。 反之亦然 - 值越低,OOM-Killer 干预的可能性越高,但数据库性能也越高。 默认值为 60,但如果整个数据库都适合内存,则最好将该值设置为 1。

结果

不要让 OOM-Killer 中的“杀手”吓到您。 在这种情况下,杀手将成为你系统的救星。 它“杀死”最糟糕的进程并避免系统崩溃。 为了避免使用 OOM-Killer 来终止 PostgreSQL,请设置为 vm.overcommit_memory 值 2。这并不能保证 OOM-Killer 不必干预,但会降低强制 PostgreSQL 进程终止的可能性。

来源: habr.com

添加评论