使用 80K 子分区表处理 PostgreSQL(容器)中的共享内存不足错误

问题描述 投票:0回答:2

我有 PostgreSql 15.3 作为 Docker 容器运行。 我的 docker 运行配置是

-m 512g --memory-swap 512g --shm-size=16g

使用这个配置,我加载了36B行,表和索引之间占用了大约30T。 我加载了大约 24 个并行操作,并且 pg 驱动程序正在使用连接池,因此大约有 150 个并发连接,但并非所有连接都是活动的。 我的 postgresql.conf 设置为

max_connections = 512 
max_locks_per_transaction = 1024

所有这些都运行没有任何问题。

36B行表被子分区。实际数据层大约有80,000个表。 Parent,按类别分区,每个分区按年份分区,每个分区按月份分区,每个分区按传感器id分区,即80K表的数据。

我的问题是,在我的一生中,如果没有

COUNT(*)
。事实上,我可以从单个表和月份分区进行统计,但不能从年份分区进行统计,年份分区只有大约 10K 个表。
读到我需要锁表来保存共享内存中的 max_connection * max_locks ,我尝试降低 max_connections ,并增加 max_locks 和共享内存,但没有成功。
目前我在

out of shared memory, you might need to increase max_locks_per_connection

用于容器和

-m 512g --memory-swap 512g --shm-size=64g

在配置中,当然是增量的。

我确实有第二个表以相同的方式分区,数据量小得多,但也有 80K 表的数据。 根据我读到的内容,类似

max_connections = 8 max_locks_per_transaction = 163840

应该覆盖160K的表,如果每个锁占用168字节,则共享内存至少需要26M。

关于我应该修改什么以及应该如何计算目标值有什么建议吗?

postgresql docker shared-memory postgresql-15
2个回答
2
投票
max_connections = 100 max_locks_per_transaction = 1600

的数量应该能够在具有平面分区的无索引表的简单情况下处理 80000 个表,但索引也需要在规划期间锁定,即使它们最终没有在执行中使用。深层分区结构还需要更多的锁,但是如果没有测试脚本来重现您的确切结构,我还没有测试过它需要多少个。

分区越多,处理分区就会变得越来越笨重。在达到硬限制之前,这将对您可以拥有的分区数量施加实际限制。我想说你已经超出了实际限制。

这些问题只是 PostgreSQL 内部的问题。如果您在操作系统/虚拟机级别遇到内存问题,我预计这些问题会失败,并显示与您看到的不同的错误消息。

无论表已填充还是仅存在但为空,锁定问题都应该是相同的,因此如果您需要测试某些东西,只需导出不带数据的结构(如

max_connections * max_locks_per_connection

)就应该很容易做到。

    


0
投票
你的分区太多

”。

但是,我的特定问题的实际解决方案在于PostgreSql docker映像的行为,特别是如果在附加到容器的配置文件中进行修改,它似乎会忽略pg_dump -s。它需要作为

max_locks_per_transaction
选项传递到
docker run
命令行。
感谢@jjanes 建议验证值是否已读取。

当您运行 postgres 容器时,您可以附加自己的配置文件:

-c

当然,您通常需要停止并重新启动容器来修改配置设置。
如果你修改配置文件

$ # run postgres with custom config $ docker run -d --name some-postgres -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf postgres -c 'config_file=/etc/postgresql/postgresql.conf'

(一些非默认号码),

启动容器,然后发出

max_connections = 333

现在对 
SELECT name, setting FROM pg_settings WHERE name = 'max_connections'; name | setting -----------------+--------- max_connections | 333

max_locks_per_transaction
图像执行相同的操作,无论您将其设置为什么
postgres:15.3

这在
无法更改docker中的max_locks

更改github操作的max_locks中有所暗示 配置

似乎

仅在通过命令行 name | setting ---------------------------+--------- max_locks_per_transaction | 256 传递时才会受到尊重

docker run

一旦我这样做了,并将 
$ docker run -d --name some-postgres -v "$PWD/my-postgres.conf":/etc/postgresql/postgresql.conf postgres -c 'config_file=/etc/postgresql/postgresql.conf' -c max_locks_per_transaction=1024

设置为一个可笑的数字(500,000),我就能够针对下一个更高的分区级别发出计数。

也就是说,我的问题的第二个解决方案在于围绕这个问题的大多数讨论似乎都没有提到的细节。 

max_locks_per_transaction

不仅需要涵盖所有分区表的数量,

还需要涵盖其中的每个索引。再次感谢@jjanes。
就我而言,每个表大约有 10 个索引。针对一张表的查询需要 11 个锁。针对月份分区需要 21,000 个锁,针对年份分区需要 218,000 个锁。显然不可持续。

令人警醒的事实是,PostgreSql 分区不像许多其他功能那样能够轻松地水平扩展,并且可能无法很好地匹配您的业务域的逻辑组织。

© www.soinside.com 2019 - 2024. All rights reserved.