PostgreSQL 服务器在关闭来自 PHP/Laravel 客户端的连接之前不会释放内存

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

我有一个用 PHP/Laravel 编写的守护进程,它使用 PDO 连接到 PostgreSQL 数据库并从队列中执行作业。一个作业通常需要 30 分钟才能运行。它由几个使用 PostGIS 的 PostgreSQL 查询组成。

随着每个 SQL 查询服务器内存使用量的增加。仅当连接关闭时才会释放内存。因此,如果我连续运行多个作业,服务器最终会耗尽内存。

我已经能够通过让我的守护进程定期重新连接到数据库来暂时解决问题。 但是,为什么除非我断开与服务器的连接,否则内存不会被释放?


关于环境的一些细节:

在查询中,我使用 PostGIS 函数

ST_Contains()
ST_GeomFromText()
ST_Area()
用于 SELECT 和其他具有类似更新的简单纯 SQL SELECT。

查询示例:

select id
from gtn
where ST_Contains(geo_polygon::geometry, ST_GeomFromText('POINT(0.000000 0.000000)', 4326))
order by ST_Area(geo_polygon::geometry) asc;

所有 PostgreSQL 设置都是默认的,除了一个:

effective_cache_size = 1GB

使用此工具调整设置没有帮助:

# DB Version: 12
# OS Type: linux
# DB Type: web
# Total Memory (RAM): 4 GB
# CPUs num: 2
# Data Storage: ssd

max_connections = 200
shared_buffers = 1GB
effective_cache_size = 3GB
maintenance_work_mem = 256MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 2621kB
min_wal_size = 1GB
max_wal_size = 4GB
  • 使用 PHP PDO 连接到 PostgreSQL;
  • Laravel:v5.7.29;
  • PHP:
PHP 7.4.33 (cli) (built: Nov 15 2022 06:05:55) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.33, Copyright (c), by Zend Technologies
    with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans
  • Docker 镜像:postgres:12;
  • PostgreSQL:
# psql --version
psql (PostgreSQL) 12.13 (Debian 12.13-1.pgdg100+1)
  • PostGIS:
# psql -U postgres -c 'SELECT PostGIS_Full_Version();'
                                                                                          postgis_full_version          
                                                                                
------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------
 POSTGIS="3.3.2 4975da8" [EXTENSION] PGSQL="120" GEOS="3.7.1-CAPI-1.11.1 27a5e771" PROJ="Rel. 5.2.0, September 15th, 201
8" LIBXML="2.9.4" LIBJSON="0.12.1" LIBPROTOBUF="1.3.1" WAGYU="0.5.0 (Internal)"
(1 row)

另外,我找到了this,但是没有任何解决方案。

更新:2023-02-18

正如 jjanes 所说,我已经使用 PHP PDO(根本没有 Laravel)和 psql CLI 执行了以下查询 100 次:

select id
from gtn
where "view" is not null
    and geo_polygon is not null
    and ST_Contains(geo_polygon::geometry, ST_GeomFromText('POINT(0.000000 0.000000)', 4326))
order by ST_Area(geo_polygon::geometry) asc
limit 2;

在此之后,postgres 进程的内存增加了 50 Mb,包括 PHP PDO 和 psql CLI。只有在与数据库断开连接后,内存才会被释放。

然后我运行简单查询 100 次:

select id from gtn limit 100;

当我的内存只增加了 1 Mb 并且在执行期间不再增加时。内存也只有在断开连接后才被释放。

使用 PHP PDO 我尝试运行

gdb
。我在 postgres 的
dockere-compose.yml
服务中添加了以下配置:

cap_add:
   - SYS_PTRACE
security_opt:
   - seccomp:unconfined

并安装了

postgresql-12-dbgsym postgresql-12-postgis-3-dbgsym gcc gdb libc6-dbg libffi6-dbg libgcc1-dbg libkrb5-dbg libstdc++6-8-dbg libxml2-dbg zlib1g-dbg libkrb5-dbg
包。

我使用 PHP PDO 再次运行我的查询,在执行查询 100 次后,

gdb
向我展示了下一个:

$ gdb -p 70

...

(No debugging symbols found in /usr/lib/x86_64-linux-gnu/libmd.so.0)
Cannot access memory at address 0x7f5264494088

warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Failed to read a valid object file image from memory.
Unable to read JIT descriptor from remote memory
0x00007f526367ad16 in epoll_wait (epfd=3, events=0x55f87ab9cfb8, maxevents=1, timeout=-1)
    at ../sysdeps/unix/sysv/linux/epoll_wait.c:30
30  ../sysdeps/unix/sysv/linux/epoll_wait.c: No such file or directory.

我什至无法为

p MemoryContextStats(TopMemoryContext)
执行
gdb
,因为我得到一个
Couldn't get extended state status: No such process.
错误。

php laravel postgresql memory postgis
1个回答
0
投票

根据 SO(thisthisthis)的一些答案,我找到了适合我的解决方案。我只是让

postgresql.conf
对我当地的发展更有礼貌:

max_connections = 30
shared_buffers = 128MB
effective_cache_size = 384MB
maintenance_work_mem = 32MB
checkpoint_completion_target = 0.9
wal_buffers = 3932kB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 1456kB
min_wal_size = 1GB
max_wal_size = 4GB
max_worker_processes = 6
max_parallel_workers_per_gather = 3
max_parallel_workers = 6
max_parallel_maintenance_workers = 3

我想资源会单独分配给每个连接,并在必要时以

max_connection
倍增。我最后的配置,
max_connections = 100
,太大了。一旦我像上面那样更改了配置,我就没有看到超过 1 Gb 的长时间重复请求,并且 OOM 不再发生。

因此,我认为我的问题是配置错误,而不是内存泄漏。

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