如何解决“错误:无法调整共享内存段大小”

免费试用

立即开始增强您的 PostgreSQL。

A fatal error red cross on a computer screen

作者:Sarah Conway

这就像任何一天一样。您在服务器上运行 PostgreSQL,突然之间,您的内存使用量激增,操作停止,并且您看到可怕的错误消息:“无法调整共享内存段大小”。

幸运的是,这是使用 PostgreSQL 时遇到的相当常见的内存故障。让我们来看看它发生的原因以及如何解决它。

此错误意味着什么

PostgreSQL 使用共享内存 来缓存页面和执行查询。因此,数据库事务通常受系统范围的分配限制,这意味着当服务器检测到内存使用量超过当前设置时,您会很快收到抛出错误的通知,并且系统将拒绝请求的操作。 

当您收到错误消息时…

错误:无法调整共享内存段大小...:设备上没有剩余空间 

…这表明 Postgres 在设备上的内存分配方面遇到了问题。幸运的是,有一个简单的解决方案:您只需要调整系统中设置的内存限制即可!在本博客文章中,我们将回顾您可以采取的几种方法来缓解此错误。

最常见的问题:共享内存参数

我们知道此错误表示由于内存使用而导致的性能瓶颈。但问题的真正原因是什么?

最常见的情况是,对共享内存段大小设置了系统限制。例如,Docker 平台的 默认共享内存大小为 64 MB,在运行任何类型的实质性工作负载或数据库操作时,很容易超过此设置。此默认值因每个操作系统而异;但是,此设置通常太低而无法处理大规模数据。 

首先,您需要先检查资源使用情况的当前状态,以确定您尝试执行的操作是否使系统过载。查看您的监控堆栈,看看是否存在瓶颈或使用高峰,并记下它尝试超过的值以及针对哪个查询。这将允许您在继续缓解错误时根据需要添加更多内存或优化查询。查看日志还将为您提供有关因该错误而被锁定的特定事务语句或长时间挂起的特定事务语句的更多信息。

可以定义特定的 PostgreSQL 日志记录参数,使您能够记录相关事件,以便在这种情况下实现最大的可观察性,例如 log_lock_waits = on(默认值为 off),以便为等待时间超过 deadlock_timeout 的查询创建已记录事件的审计跟踪。 

您可以使用 log_error_verbosity 最大化错误输出,甚至可以使用 log_statement 控制记录的 SQL 语句类型(在 noneddlmodall 之间进行选择),默认设置为 none。根据您需要识别的有问题查询或需要解决的情况的详细程度,修改这些类型的设置,以解决此错误。

一旦您对系统内实际发生的情况以及触发错误的原因有了一个很好的了解,并且确定当前正在执行的查询已优化并按预期运行并获得了适当的最终结果,您需要查看Postgres 资源消耗配置参数

您可以先检查 shared_buffers 的当前设置(设置共享内存缓冲区使用的内存限制,默认为 128 MB)。此值控制 Postgres 的数据缓存,并指示服务器启动时可用的共享内存的主要分配。当超过当前设置时,Postgres 文档建议将其设置为可用内存使用量的 25% 左右。但是,它必须至少略小于 shm_size 的当前设置(如果适用,在 Docker 系统上运行时)。

查看此博客文章,了解有关如何调整这些关键 PostgreSQL 参数以提高数据库性能的更多详细信息。

还应注意 work_mem,因为它允许您设置查询操作在写入临时磁盘之前要使用的最大内存量(默认为 4 MB)。查询允许在执行时为 EXPLAIN 计划中的每个节点和每个进程使用高达为 work_mem 定义的值的内存。当许多并行工作进程正在运行或正在处理许多表和分区时,正在使用的内存量会呈指数级增长。

如果您继续遇到问题,您还可以尝试禁用并行查询,以最大程度地减少并发操作,并将允许的操作限制为一次一个查询。启用并行工作进程后,查询执行速度会更快,但每次事务消耗的资源会更多(从而降低整体吞吐量)。可以使用 max_parallel_workers 设置来控制此功能。

在文档的“锁管理”部分,您可能还想查看 max_locks_per_transaction 的当前设置。当迭代大量表时,此限制可能会限制操作(导致此共享内存错误)。这种情况最常发生在运行逻辑备份时,因为 pg_dump 在整个备份过程中都会锁定表,这很容易触发此错误。

阅读本文以更好地了解PostgreSQL 锁

当然,在决定如何最好地计算所有这些值时,强烈建议您阅读 Postgres 文档(上面提供了链接),因为通常需要执行特定的数学运算或需要考虑其他特殊因素才能优化内存分配设置。

此外,对于每个操作系统或开发平台,您都需要确定需要调整哪些共享内存参数并相应地调整其大小。对于这种更改,您需要重新启动系统或重建云实例,以便在调整设置后使其生效。

因此,请花时间查看特定于平台的文档。这些本地化配置文件旨在覆盖 Postgres 默认值并动态分配资源,因此即使您更改了主配置文件,您仍然可能会遇到此共享内存错误。

您通常可以通过将标志传递给交互式服务器启动命令来更改这些设置(例如,在 Docker 中,将 --shm-size=256MB 作为命令行标志传递给 docker run)或更改该平台的主配置文件中的适用值(例如在 docker-compose 中,shm_size 参数将设置内存的全局默认值)。

请务必记住,某些云数据库平台确实利用了动态资源管理(例如 Google Cloud E2 VM 实例),因此您可能会发现您的更改会被持续覆盖。如果您继续遇到错误或相关问题,则应直接向托管您的 PostgreSQL 数据库的云供应商寻求支持,以确定可能需要调整的其他设置以解决此错误。

Timescale 呢?

我们的云服务 Timescale 作为 PostgreSQL 之上的扩展程序运行。因此,为 Postgres 中出现的错误推荐的任何建议(包括此博客文章的内容!)对于您的情况仍然直接有用。您仍然需要查看当前的内存和资源消耗,确定触发错误的查询,并研究上述在 Postgres 中本地使用的建议内存设置,以解决观察到的内存错误。

有关 Timescale 特定参数的其他建议,这些参数有助于您记录并进行相应调整以最大程度地提高性能并最大程度地减少错误,请查看我们的相关博客“您应该了解(和调整)的 Timescale 参数,以最大程度地提高性能”。

结论

尽管从概念上很容易理解此内存错误的原因,但要计算如何分配资源却更加困难,尤其是在寻求使这些设置尽可能经济高效并针对您的确切用例实现最佳性能时。掌握基础架构内的监控和可观察性是了解日常运营的使用模式和需求的最佳起点,尤其是在您的数据使用量随着时间的推移而增长的情况下。

使用像 Timescale 这样的云服务可以帮助您完成这项工作。借助我们的产品,您可以使用 Insights 为数据库获取开箱即用的监控仪表板,该功能专门针对数据库监控和查询优化而设计。借助 Timescale 的支持团队,您可以使用此内置功能节省创新时间和成本,并加快产品上市速度,高枕无忧,因为 Postgres 专家随时为您提供帮助。还没有使用 PostgreSQL 或 Timescale,但想使用吗?迁移协助包含在支持计划中,可帮助您确保从一个平台到另一个平台的无缝过渡。

听起来很有趣?或者,您对如何解决此错误或如何在 PostgreSQL 和 Timescale 中优化内存和资源设置有任何疑问?我们的团队随时为您提供帮助!如果您当前是 Timescale 的活跃用户,则可以使用您的基本计划获得我们的支持。随时通过 [email protected] 向我们发送电子邮件。否则,您可以免费试用 Timescale 30 天, *无需输入信用卡*(并在试用期间获得我们专家支持的全面访问权限!)。

我们期待与您联系!