PostgreSQL 9.1在Docker Ubuntu容器中备份及参数调整失败求助
咱们先把你遇到的问题拆开来分析,再一步步给出靠谱的解决办法:
为啥会出现这些状况?
1. 备份失败的核心原因
你有13200张表,用pg_dump这类工具备份时,单个备份事务需要给所有表加锁(至少是ACCESS SHARE锁)。PostgreSQL 9.1默认的max_locks_per_transaction是64——意思是单个事务最多能锁定64个对象。13200远大于64,所以备份时直接因为锁资源耗尽抛出内存不足类的错误,备份自然失败。
2. 调大max_locks_per_transaction后启动失败的原因
当你把这个参数调到1024,PostgreSQL需要的共享内存会暴增:全局锁池的大小是max_connections * max_locks_per_transaction,这个值变大后,系统(或者Docker容器)的共享内存限制没跟上,PostgreSQL启动时申请不到足够的共享内存,直接启动失败。
你改SHMMAX失败,大概率是只改了宿主机的参数,但Docker容器没继承生效,要么就是改的数值还是不够,或者修改方式不对。
具体解决步骤
步骤1:先算对合适的参数值
别直接把max_locks_per_transaction拉到1024(太浪费内存),先算个合理值:
你有13200张表,假设max_connections是默认的100,那单个事务至少需要锁定132张表(13200/100),所以把max_locks_per_transaction设为200就足够(留些余量给其他并发事务)。
另外,你容器有120G内存,shared_buffers可以设为内存的25%左右,也就是30G——这能让PostgreSQL缓存更多数据,性能更好。
步骤2:给Docker容器加足够的共享内存
Docker默认的共享内存(/dev/shm)只有64MB,这对你的大库来说完全不够。必须显式调大:
- 如果是新建容器,启动时加参数:
给16G共享内存足够用了,毕竟你有120G内存可以分配。docker run -d --shm-size=16g ... 你的PostgreSQL镜像名 - 如果是已有容器,用docker-compose的话,在配置文件里加:
然后重启容器就行。services: postgres: # 其他配置... shm_size: '16gb'
步骤3:同步调整共享内存参数
3.1 修改postgresql.conf
找到容器里的postgresql.conf(一般在/var/lib/postgresql/9.1/main/),修改这两个参数:
max_locks_per_transaction = 200 shared_buffers = 30GB
保存后重启PostgreSQL。
3.2 确保容器内的SHM参数生效
进入容器,先检查当前的共享内存限制:
docker exec -it 你的容器名 bash cat /proc/sys/kernel/shmmax cat /proc/sys/kernel/shmall
如果数值太小,临时调整(重启容器会失效,最好启动容器时带参数):
sysctl -w kernel.shmmax=34359738368 # 设为32G,比shared_buffers大一点 sysctl -w kernel.shmall=8388608 # 对应32G(每页4KB)
或者启动容器时直接传递这些参数:
docker run -d --shm-size=16g --sysctl kernel.shmmax=34359738368 --sysctl kernel.shmall=8388608 ... 你的镜像名
步骤4:验证启动和备份
修改完后启动PostgreSQL:
docker exec -it 你的容器名 pg_ctl start
启动成功后,再尝试备份:
pg_dump -U 你的用户名 -d 你的数据库名 > backup.sql
额外提醒
PostgreSQL 9.1是2011年的老版本了,2023年已经完全停止支持,不仅有安全漏洞,对大量表的场景优化也很差。强烈建议升级到14或15版本,新版本在锁管理、内存使用上有很多改进,能更轻松处理你的13200张表。
如果备份还是有问题,也可以试试分批次备份(比如按schema分着备份),减少单个事务需要锁定的表数量,这样也不用调太大的锁参数。
内容的提问来源于stack exchange,提问作者Maddy

