在Linux上为PostgreSQL配置内存不足杀手


当数据库服务器在Linux上意外关闭时,您需要查找原因。 可能有几个原因。 例如, SIGSEGV-由于后端服务器中的错误而崩溃。 但这是罕见的。 通常,磁盘空间或内存会耗尽。 如果磁盘空间用完,一种解决方法是释放空间并重新启动数据库。


内存不足的杀手


当服务器或进程的内存不足时,Linux提供了两种解决方案:使整个系统崩溃或终止消耗内存的进程(应用程序)。 当然,最好完成此过程并保存操作系统以免异常终止。 简而言之,Out-Of-Memory Killer是终止应用程序以免崩溃保存内核的过程。 他牺牲了应用程序以保持操作系统运行。 让我们首先讨论OOM如何工作以及如何控制它,然后看看OOM Killer如何决定要结束的应用程序。


Linux的主要任务之一是在需要时为进程分配内存。 通常,进程或应用程序从OS请求内存,但是它们本身并未完全使用它。 如果操作系统将内存分发给要求它的每个人,但不打算使用它,则内存很快就会终止,并且系统将发生故障。 为避免这种情况,操作系统会为该进程保留内存,但实际上不会发出该内存。 仅在进程真正要使用内存时才分配内存。 碰巧OS没有可用内存,而是为进程分配了内存,并且当进程需要时,OS会分配内存。 缺点是,有时OS会保留内存,但在正确的时间没有可用的内存,并且系统崩溃。 OOM在这种情况下起着重要的作用,并终止进程以防止内核崩溃。 强制终止PostgreSQL进程后,日志中将显示一条消息:


Out of Memory: Killed process 12345 (postgres). 

如果系统中的内存很少并且无法释放它,则out_of_memory函数。 在此阶段,她只剩下一件事-完成一个或多个过程。 OOM-killer应该立即终止该过程还是我可以等待? 显然,当调用out_of_memory时,这是由于等待I / O操作或页面交换到磁盘。 因此,OOM杀手必须首先执行检查,然后根据检查结果确定应该完成该过程。 如果以下所有检查均得出肯定的结果,则OOM将终止该过程。


工艺选择


当内存用完时,将out_of_memory()函数。 它具有一个函数select_bad_process() ,该函数从badness()函数接收一个估计值。 分布最“坏”的过程。 badness()函数根据某些规则选择一个进程。


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

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


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

Postgres进程的标识符是3813,因此在另一个Shell中,您可以使用以下oom_score内核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 

或在rcctl使用oomprotect


 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中的杀手吓到。 在这种情况下,杀手will将是您系统的救星。 它“杀死”了最差的进程,并使系统免于异常终止。 为避免必须使用OOM-Killer完成PostgreSQL,请将vm.overcommit_memory为2。这不能保证OOM-Killer不必干预,但可以减少PostgreSQL进程被迫终止的可能性。

Source: https://habr.com/ru/post/zh-CN464245/


All Articles