调试高 PostgreSQL 内存使用率(每个连接)
Debugging high PostgreSQL memory usage (per connection)
有什么方法可以检查分配给每个连接的内存实际使用情况吗?
从 PostgreSQL 9.3 升级到 PG 12 后,每个 PostgreSQL 连接的内存使用量增加了一倍甚至三倍。所以我不得不从 32GB 机器开始:
shared_buffers = 8GB
用于连接的内存 = 8GB
磁盘缓冲区内存 = 16GB
到:
64GB 机器:
shared_buffers = 8GB
用于连接的内存 = 40GB
磁盘缓冲区内存 = 16GB
而且还不够。单个连接使用 170MB 私有 ram([=12= 中的 Private
,如 https://www.depesz.com/2012/06/09/how-much-ram-is-postgresql-using/ 中所述),不与其他进程共享的情况并不少见。
内存使用率如此之高的原因是什么?据我所知,它是持久的——直到连接关闭,内存才会被释放。当我使用由 Wildfly 管理的连接池时,它们会被重复使用,并且很少会被关闭和重新创建。
这是我的数据源定义:
<datasource jta="true" jndi-name="java:/MainDS" pool-name="MainDCPool">
<connection-url>jdbc:postgresql://dbhost/</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<driver>postgres</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>30</max-pool-size>
</pool>
<security>
<user-name>dbuser</user-name>
<password>password</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/>
<validate-on-match>true</validate-on-match>
<background-validation>false</background-validation>
</validation>
<statement>
<share-prepared-statements>false</share-prepared-statements>
</statement>
<timeout>
<idle-timeout-minutes>1</idle-timeout-minutes>
</timeout>
</datasource>
据我所知,告诉设置 'idle-timeout-minutes=1' 和 min-pool-size=1
没有太大影响。看起来 WildFly 从池中选择随机连接(当应用程序请求时),因此它们中的任何一个都不太可能长时间保持空闲并且池大小永远不会低于 ~20 个连接
原来原因是直方图 (pg_stats)。每个连接都将它存储在内存中,并且在具有大量分区的数据库中会导致大量开销。包含 large/long 值的列具有重大影响。降低单个 table 的 4 列及其分区的 STATISTICS 属性可将内存使用量(每个连接)减少 35%。
升级本身并没有错,但是 - 作为升级过程的一部分 - 分析了整个数据库,将新的 default_statistics_target
值应用于所有 table。
检查直方图大小:Finding the histogram size for a given table PostgreSQL
有什么方法可以检查分配给每个连接的内存实际使用情况吗?
从 PostgreSQL 9.3 升级到 PG 12 后,每个 PostgreSQL 连接的内存使用量增加了一倍甚至三倍。所以我不得不从 32GB 机器开始: shared_buffers = 8GB 用于连接的内存 = 8GB 磁盘缓冲区内存 = 16GB 到: 64GB 机器: shared_buffers = 8GB 用于连接的内存 = 40GB 磁盘缓冲区内存 = 16GB
而且还不够。单个连接使用 170MB 私有 ram([=12= 中的 Private
,如 https://www.depesz.com/2012/06/09/how-much-ram-is-postgresql-using/ 中所述),不与其他进程共享的情况并不少见。
内存使用率如此之高的原因是什么?据我所知,它是持久的——直到连接关闭,内存才会被释放。当我使用由 Wildfly 管理的连接池时,它们会被重复使用,并且很少会被关闭和重新创建。
这是我的数据源定义:
<datasource jta="true" jndi-name="java:/MainDS" pool-name="MainDCPool">
<connection-url>jdbc:postgresql://dbhost/</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<driver>postgres</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>30</max-pool-size>
</pool>
<security>
<user-name>dbuser</user-name>
<password>password</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.postgres.PostgreSQLValidConnectionChecker"/>
<validate-on-match>true</validate-on-match>
<background-validation>false</background-validation>
</validation>
<statement>
<share-prepared-statements>false</share-prepared-statements>
</statement>
<timeout>
<idle-timeout-minutes>1</idle-timeout-minutes>
</timeout>
</datasource>
据我所知,告诉设置 'idle-timeout-minutes=1' 和 min-pool-size=1
没有太大影响。看起来 WildFly 从池中选择随机连接(当应用程序请求时),因此它们中的任何一个都不太可能长时间保持空闲并且池大小永远不会低于 ~20 个连接
原来原因是直方图 (pg_stats)。每个连接都将它存储在内存中,并且在具有大量分区的数据库中会导致大量开销。包含 large/long 值的列具有重大影响。降低单个 table 的 4 列及其分区的 STATISTICS 属性可将内存使用量(每个连接)减少 35%。
升级本身并没有错,但是 - 作为升级过程的一部分 - 分析了整个数据库,将新的 default_statistics_target
值应用于所有 table。
检查直方图大小:Finding the histogram size for a given table PostgreSQL