PostgreSQL参数优化

内存配置优化

PostgreSQL中与内存有关的配置参数如下。

  • shared_buffers:共享缓存区的大小,相当于Oracle数据库中的SGA,主要做数据块的缓存。

  • work_mem:为每个进程单独分配的内存,主要用于排序、HASH等操作。

  • maintence_work_mem:为每个进程单独分配的内存,主要是进行维护操作时需要的内存,如VACUUM、CREATE INDEX、ALTER TABLE ADD FOREIGN KEY等操作需要的内存。

  • autovacuum_work_mem:从PostgreSQL 9.4版本开始新增的参数。在PostgreSQL 9.4之前的版本中,AutoVacuum的每一个worker进程与手动做VACUUM一样,分配的内存大小都是由maintence_work_mem参数控制的,现在分开了,AutoVacuum的worker进程由该参数控制,手动VACUUM时分配的内存大小仍由maintence_work_mem参数控制。此参数默认设置为“-1”,即与原先的行为是一样的,当把此参数设置为其他值时,可以为AutoVacuum的每个worker进程做VACUUM操作时指定不同的内存值。

  • temp_buffers:指定临时表的缓存的大小,这是为每个不同的进程单独分配的内存,不在共享内存中。默认为8MB,通常保持默认值就可以了。

  • wal_buffers:指定WAL日志缓存的大小,默认值是“-1”,即会根据shared_buffer的大小自动设置。选择等于shared_buffers的1/32的尺寸(大约3%),但是不小于64KB也不大于WAL文件的尺寸(通常为16MB)。不应该超过WAL文件的大小,通常保持默认值就可以了,如果手动设置,一般为4MB~16MB。

  • huge_pages:是否使用大页,默认设置是“try”,表示尽量使用大页,如果操作系统未开启大页或分配的大页内存太小,数据库虽仍然能启动,但不再使用大页内存。

  • effective_cache_size:该参数实际上与具体的内存分配没有关系,它是告诉优化器在估计SQL的执行代价时假设有多少磁盘缓存,注意主要指文件系统缓存,通常设置为机器总内存的80%,设置得多一些(如90%)或少一些(如50%)并不会有严重的影响。shared_buffers,即共享缓存区的大小,因为要多个进程中共享,所以必须使用共享内存技术来存放。PostgreSQL的数据文件都在文件系统中,操作系统的文件系统也有缓存,这有可能会导致数据库的数据块除了在PostgreSQL的共享内存中有一个副本以外,在文件系统的缓存中也有一个副本,因此造成内存利用率不高,这就是PostgreSQL中的DoubleBuffering问题。在Oracle数据库中,通过设置Direct I/O来避免双缓存问题,但PostgreSQL中未实现对Direct I/O的支持。为了减少双缓存问题带来的影响,通常使用以下方法解决:

    设置较小的shared buffer,将大多数内存给文件系统缓存使用,如在一台有24GB内存的机器上,可以把PostgreSQL中的shared buffer设置为较小值,如500MB~1GB,其他内存都留给文件系统缓存使用。

设置信号

kernel.sem=5010 3256500 5010 650

大页内存的配置

对一些连接数很大且内存较大的PostgreSQL数据库,强烈建议配置大页。这不仅是因为大页的性能会高一些,也是为了避免页表过大。操作系统把逻辑地址映射成物理地址时,需要把映射关系也存储到一个内存中,这部分内存就是页表。在Linux操作系统中,即使是同一块共享内存,每个进程中的逻辑地址也是不相同的,因此不同进程中的映射表项也不相同。在64位的机器上,每个4k页需要占用大约8字节的内存,一台48GB内存的机器,如果分配了24GB共享内存,则每个进程的页表大小为(24G/4k)×8=48MB,如果服务器连接上500个进程,页表的大小将是500×48=24GB。这会立刻把机器上所有内存吃光,因而会产生很大的问题。当然并不是每个新连接一连接上来,后面进程的页表就会马上分配48MB,当进程需要建立逻辑地址与物理地址之间的关系时才会分配,所以进程占用的页表空间是缓慢增加的,但最终还是可能会占用很大的页表内存。

要查看是否存在这个问题,可以使用如下命令来检查页表的大小:

cat /proc/meminfo |grep PageTables

如果发现页表的大小不是几十兆,而是达到了1GB以上,就说明数据库存在此问题。

PostgreSQL 9.4版本开始支持大页,打开大页的方法是设置参数“huge_pages”,命令如下:

huge_pages = try

操作系统中大页的设置项在/etc/sysctl.conf中,命令如下:

vm.nr_hugepages=10240

上例表示设置了大小为10240*2MB的内存,即大约为20GB内存。使用如下命令让该设置生效:

sysctl -p

cat /proc/sys/vm/nr_hugepages

最后还有一个需要注意的问题,即Linux中还有一个透明大页(Transparent Hugepage),即Linux自动进行大小页的转换和自动管理,但目前在Redhat 7.X/CentOS 7.X下该功能会带来性能的抖动或下降,通常建议关闭透明大页,关闭方法如下:

grubby --update-kernel=ALL --args="transparent_hugepage=never

VACUUM中的优化

访问在共享内存中的数据块数×vacuum_cost_page_hit+访问在磁盘上的数据块数×vacuum_cost_page_miss+修改干净的在磁盘中的数据块数×vacuum_cost_page_dirty这些参数的意义如下:

  • vacuum_cost_page_hit:VACUUM访问的数据块在共享内存中的代价值,默认为“1”。
  • vacuum_cost_page_miss:VACUUM访问的数据块不在共享内存中的代价值,默认为“10”。
  • vacuum_cost_page_dirty:VACUUM改变一个非脏数据块为脏数据块的代价值,默认为“20”。

要想减少执行VACUUM命令对现有系统的影响,可以把vacuum_cost_delay设置为一个合适的值,命令如下:

osdba=# set vacuum_cost_delay to 1;
SET
osdba=# vacuum;
VACUUM

但有时把vacuum_cost_delay设置为最小值1时,VACCUM操作的执行效率还是太低,这是因为默认的vacuum_cost_limit值太小,vacuum_cost_limit默认是“200”,如果是SSD硬盘可以把该值设置为“10000”,如果是一般带缓存的硬件Raid卡输出的机械硬盘,设置为1000~2000比较合适。

对于自动VACUUM即AutoVacuum,也有一组与上面类似的参数来实现相同的功能。

  • autovacuum_vacuum_cost_delay:PostgreSQL 12及以上版本默认是“2ms”,而PostgreSQL 11及之前版本默认值是“20ms”,20ms这个值通常太大了,改成2ms比较合适。
  • autovacuum_vacuum_cost_limit:默认值是“-1”,即使用vacuum_cost_limit的值,前面讲过,通常此默认值会较低,如果是SSD硬盘可以把该值设置为“10000”,如果是一般带缓存的硬件Raid卡输出的机械硬盘,则设置为1000~2000比较合适。我们可以看到这些参数前都加了“autovacuum_”。还有一个参数可用于指定启动AutoVacuum的work进程的多少,即autovacuum_max_workers,默认值为“3”。当发现来不及AutoVacuum时,可以把此参数值调得大一些。

通常一张表变更的行数超过一定的阈值时,AutoVacuum才会对这张表做VACUUM,该阈值的计算公式如下:

autovacuum_vacuum_scale_factor×表上记录数+autovacuum_vacuum_threshold

公式中的各参数说明如下。

  • autovacuum_vacuum_threshold:当表上发生变化的行数至少达到此参数值时,才可能让AutoVacuum对其进行VACUUM,(这里说“可能”是因为还有另一个参数“autovacuum_vacuum_scale_factor”同时控制VACUUM的执行条件),默认值为“50”。也可以在表上单独设置此参数,让不同的表有不同的配置。

  • autovacuum_vacuum_scale_factor:触发VACUUM的第二个阈值条件。调整这两个参数的值可以改变AutoVacuum的工作量,从而提升性能。对于一些大表,autovacuum_vacuum_scale_factor设置为“50”有一些小了,可以在大表上单独设置一个较大的值,如“90”,命令如下

      alter table big_table set (autovacuum_vacuum_threshold=90,toast.autovacuum_vacuum_threshold=90);
    

配置的最佳实践

  1. 禁止SELinux

    SELinux的限制很多,为了操作方便,我们会关闭SELinux,关闭的方法是修改/etc/selinux/config:

     SELINUX=disabled
     getenforce
    
  2. 关闭防火墙

     systemctl stop iptables
     systemctl disable iptables
    
     systemctl stop firewalld
     systemctl disable firewalld
    
  3. ulimit的配置

     * soft nofile 65536
     * hard nofile 65536
     * soft nproc 131072
     * hard nproc 131072
     * soft memlock -1
     * hard memlock -1
    
  4. XFS文件系统的配置

     /dev/sde /data xfs nodev,discard,noatime,inode64,allocsize=16m 0 
    
  5. 设备的I/O调度策略设置

     grubby --update-kernel=ALL --args="elevator=deadline"
    
  6. 设置内存大页

     grubby --update-kernel=ALL --args="transparent_hugepage=never"
    

    设置页面大小为1GB的大页共32GB,命令如下

     grubby --update-kernel=ALL --args="default_hugepagesz=1G hugepagesz=1G hugepages=32"
    
  7. sysctl.conf的配置

     vm.swappiness=0
     vm.overcommit_memory=2
     vm.overcommit_ratio=85
     vm.dirty_background_ratio=1
     vm.dirty_ratio=2
     kernel.shmmax = 274877906944
     kernel.shmall = 67108864
     kernel.sem=20 13000 20 650
     kernel.sysrq = 1
     kernel.core_uses_pid = 1
     kernel.msgmnb = 65536
     kernel.msgmax = 65536
     kernel.msgmni = 2048
     net.ipv4.tcp_syncookies = 1
     net.ipv4.ip_forward = 0
     net.ipv4.conf.default.accept_source_route = 0
     net.ipv4.tcp_tw_recycle = 1
     net.ipv4.tcp_max_syn_backlog = 4096
     net.ipv4.conf.all.arp_filter = 1
     net.ipv4.ip_local_port_range = 1025 65535
     net.core.netdev_max_backlog = 10000
     net.core.rmem_max = 2097152
     net.core.wmem_max = 2097152
     net.core.somaxconn = 2048
    

    上面的一些重要配置项的说明如下。

    • vm.swappiness=0:让操作系统尽量不要使用SWAP。对于数据库主机来说,尽量不使用SWAP能获得更好的性能。
    • vm.overcommit_memory=2:将此参数设置为“2”是为了防止OOM。此参数的默认值是“0”,0表示程序分配的内存可以大于实际拥有的物理内存,因为分配内存时,只是分配的虚拟内存,还没有实际分配物理内存。如果分配的总虚拟内存超过物理内存,当所有的程序都马上要使用内存,而物理内存不够时,操作系统只能kill掉一些程序,释放一些内存才能保证其他程序继续运行,这就出现了OOM Kill。如果OOM杀掉的是PostgreSQL数据库的进程,数据库就会宕机。OOM本质上是内存“超售”导致的。如果把该参数设置成“2”,再配合下面的参数vm.overcommit_ratio就可以避免OOM。当此参数配置为“2”时,程序分配内存时,如果内核发现分配的内存超过了限制,则会直接报错,而不会到内存不够用时再kill掉占内存大的进程。如果此参数设置为“2”,内存不够时,PostgreSQL数据库只是无法建立新连接,而不会发生OOM Kill,这就安全了很多。内核认为能允许分配内存的最大值是总共的物理内存×vm.overcommit_ratio%+SWAP空间。我们这台机器的内存是256GB,SWAP空间是32GB,256×0.85+32=249.6GB,算出来的结果没有超过总内存,这是安全的。所以当把该参数设置为“2”时,还需要根据总内存和SWAP空间的大小,设置合理的vm.overcommit_ratio的参数值。
    • vm.overcommit_ratio=85:见上面的描述。
    • vm.dirty_background_ratio=1:是一个百分比,默认值是“10%”,当文件系统的缓存中保存的脏页数超过总内存的这个百分比时,开始后台刷脏数据。默认值太大,当内存中有大量的脏数据时,会产生很大的性能抖动。为了保证系统的稳定性,建议把该值设置成一个较小的值。
    • vm.dirty_ratio=2:与上一参数类似,只是前台刷脏页的百分比,默认值是“20%”,也太大,建议设置成“1%”。
    • kernel.shmmax=274877906944:设置成与总内存一样。
    • kernel.shmall=67108864:设置成总内存的页面数。
    • kernel.sem=20 13000 20 650:12.5.1节中已介绍过这个参数

数据库参数配置

listen_addresses = '*' # what IP address(es) to listen on;
port = 5432 # (change requires restart)
max_connections = 3000 # (change requires restart)
superuser_reserved_connections = 10 # (change requires restart)
tcp_keepalives_idle = 5 # TCP_KEEPIDLE, in seconds;
tcp_keepalives_interval = 5 # TCP_KEEPINTVL, in seconds;
tcp_keepalives_count = 3 # TCP_KEEPCNT;
shared_buffers = 32GB
huge_pages = on
# you actively intend to use prepared transactions.
work_mem = 4MB
maintenance_work_mem = 128MB
autovacuum_work_mem = 256MB
wal_writer_delay = 10ms
max_wal_size = 50GB
min_wal_size = 40GB
checkpoint_timeout = 15min
max_locks_per_transaction =256
checkpoint_completion_target = 0.9 # checkpoint target duration, 0.0 - 1.0
effective_cache_size = 256GB
log_destination = 'csvlog' # Valid values are combinations of
logging_collector = on # Enable capturing of stderr and csvlog
log_directory = 'pg_log' # directory where log files are written,
log_truncate_on_rotation = on # If on, an existing log file with the
log_rotation_age=3d
log_rotation_size=100MB
autovacuum = on # Enable autovacuum subprocess? 'on'
log_autovacuum_min_duration = 0
autovacuum_max_workers = 10 # max number of autovacuum subprocesses
autovacuum_naptime = 1min # time between autovacuum runs
autovacuum_vacuum_threshold = 500 # min number of row updates before vacuum
autovacuum_analyze_threshold = 500 # min number of row updates before analyze
autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
autovacuum_vacuum_cost_delay = 2ms # autovacuum_vacuum_cost_delay
autovacuum_vacuum_cost_limit = 5000 # default vacuum cost limit
wal_compression = on
lock_timeout=600000
statement_timeout=3600000
log_min_error_statement=error
log_min_duration_statement=5s
temp_file_limit=20G #控制临时表空间size
vacuum_cost_limit = 5000 #sas 盘2000,SSD为10000
vacuum_cost_delay = 2ms
checkpoint_completion_target=0.9
random_page_cost = 1.1
log_checkpoints =on
log_statement = 'ddl'
idle_in_transaction_session_timeout = 600000 # 自动清理 idle session
track_io_timing = on
track_functions = all
shared_preload_libraries = 'pg_stat_statements'
track_activity_query_size = 2048
pg_stat_statements.max = 10000
pg_stat_statements.track = all
pg_stat_statements.track_utility = off
pg_stat_statements.save = on
archive_mode = 'on'
archive_command = '/usr/bin/true'

一些重要配置项的说明如下。

  • 配置了TCP的keepalive选项,tcp_keepalives_idle、tcp_keepalives_interval、tcp_keepalives_count,让一些已出问题的网络连接能尽快结束。
  • shared_buffers=32GB:需要与大页内存配置保持一致。
  • huge_pages=on:从默认值“try”改为“on”,这样会强制保证数据使用大页内存,如果操作系统配置的大页有问题,则数据库无法启动,这样可以快速发现问题。
  • max_wal_size=50GB:指定WAL日志的空间上限。保证WAL不会占用太多的空间。
  • min_wal_size=40GB:该值通常不要设置得太小,容易导致Standby失效。
  • checkpoint_timeout=15min:保证能及时发生Checkponit。
  • autovacuum_max_workers=10:worker设置得多一些,可以保证AutoVacuum能尽快地完成。
  • autovacuum_vacuum_cost_delay=2ms:为防止AutoVacuum对系统产生太大冲击,AutoVacuum每完成一定的工作量,就休眠2ms再重新开始工作。
  • autovacuum_vacuum_cost_limit=5000:因为是SSD,所以建议把该值设置得高一些。
  • vacuum_cost_limit=5000:因为是SSD,所以建议把该值设置得高一些。
  • vacuum_cost_delay=2ms:为防止Vacuum对系统产生冲击,Vacuum每完成一定的工作量后,休眠2ms再开始工作。
  • log_destination=‘csvlog’:设置成csv格式,便于分析日志。
  • lock_timeout=600000:当锁超过600秒时,则放弃锁,防止长时间持有锁。如果你有长时间的DDL或DML语句操作,请根据实际情况把该参数值改大。
  • statement_timeout=3600000:允许SQL最多运行1小时,请根据实际情况调整此参数。
  • idle_in_transaction_session_timeout=600000:清理长时间(10分钟)的idle的事务连接,请根据实际情况调整此参数。
  • archive_mode=‘on’:打开归档。
  • archive_command=‘/usr/bin/true’:这里虽然设置了,但设置的是一个无用的命令,主要是因为修改archive_mode需要重启数据库服务器,而修改archive_command不需要重启数据库服务器。所以先配置一个无用的命令“/usr/bin/true”,等真正需要归档时,再把archive_command设置成实际的归档命令,这样就不需要重启机器了。
  • random_page_cost=1.1:因为是SSD,将该值调小,以便于执行计划尽量走索引,而不走全表扫描。
  • shared_preload_libraries=‘pg_stat_statements’:pg_stat_statements插件可以监控SQL的执行时间等性能统计数据,最好装上。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值