暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL 让pg_prewarm插件来给朕暖暖身子

前言

以前学习 MySQL InnoDB引擎时,可以在数据库关闭时,将内存缓冲区的信息 dump到一个文件内部,然后启动时通过加载该文件内部的块,实现对内存缓冲区的预热,从而提高数据库重启后的查询性能。而PostgreSQL也有这种功能,只需要安装pg_prewarm插件即可。更好的消息是pg_prewarm插件融入了 PostgreSQL发行版中,无需下载编译安装程序。

pg_prewarm使用

按照官方文档 PostgreSQL 13的说明,预热有两种方式,一种是手动调用pg_prewarm函数,用于将当前所需的数据装入内存。另一个选择是自动执行,要要设置shared_preload_libraries参数。设置完毕后,系统将自动运行一个后台工作进程,它定期将shared_buffer中的内容写入到文件 autoprewarm. blocks中,以便在重新启动数据库后,快速加载该文件内部的数据块,实现预热功能。

我们来使用虚拟机测试一下,我的虚拟机内存2G,我把shared_buffer为512MB,我们创建一个150MB的表。

postgres=# alter system set shared_preload_libraries='pg_prewarm';
ALTER SYSTEM

[postgres@centos8 ~]$ pgbench -i -s10 -Upostgres pgbench -p5432 
dropping old tables...
NOTICE:  table "pgbench_accounts" does not exist, skipping
NOTICE:  table "pgbench_branches" does not exist, skipping
NOTICE:  table "pgbench_history" does not exist, skipping
NOTICE:  table "pgbench_tellers" does not exist, skipping
creating tables...
generating data (client-side)...
1000000 of 1000000 tuples (100%) done (elapsed 0.83 s, remaining 0.00 s)
vacuuming...
creating primary keys...
pdone in 1.52 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 0.92 s, vacuum 0.25 s, primary keys 0.35 s).

pgbench=# select pg_size_pretty(pg_total_relation_size('pgbench_accounts'));
 pg_size_pretty 
----------------
 150 MB
(1 row)

然后重启数据库,重启后可以看到多了一个进程postgres: autoprewarm master

[postgres@centos8 ~]$ ps -ef | grep postgres
root        2487    2465  0 06:32 pts/0    00:00:00 su - postgres
postgres    2488    2487  0 06:32 pts/0    00:00:00 -bash
postgres    2586       1  0 06:43 ?        00:00:00 /data/postgresql/pgsql/13.1/bin/postgres
postgres    2588    2586  0 06:43 ?        00:00:00 postgres: checkpointer 
postgres    2589    2586  0 06:43 ?        00:00:00 postgres: background writer 
postgres    2590    2586  0 06:43 ?        00:00:00 postgres: walwriter 
postgres    2591    2586  0 06:43 ?        00:00:00 postgres: autovacuum launcher 
postgres    2592    2586  0 06:43 ?        00:00:00 postgres: stats collector 
postgres    2593    2586  0 06:43 ?        00:00:00 postgres: autoprewarm master 
postgres    2594    2586  0 06:43 ?        00:00:00 postgres: logical replication launcher 
postgres    2595    2488  0 06:43 pts/0    00:00:00 ps -ef
postgres    2596    2488  0 06:43 pts/0    00:00:00 grep --color=auto postgres

现在,我们使用 run全表扫描的sql测试。

首次运行shared hit 2144,read 14250。

再运行一次shared hit 2176,read 14218。shared buffer命中有所提高,我们想把全部缓存到内存,多执行几次就行了。若要立即完成,则必须手工执行pg_prewarm函数。

手动执行后,可以看到现在全部都已经是shared_hit了。

还可以看一下我们的autoprewarm.blocks
文件,这5列记录的分别是数据库的oid,表空间的oid,relfilenode,数据文件的ForkNumber和BlockNumber。

cat /data/postgresql/pgdata
[postgres@centos8 pgdata]$ more autoprewarm.blocks
<<16773>>
0,1664,1262,0,0
41029,1663,41042,0,4345
41029,1663,41042,0,4344
41029,1663,41042,0,4343
41029,1663,41042,0,4342
41029,1663,41042,0,4341
41029,1663,41042,0,4340
41029,1663,41042,0,4339
41029,1663,41042,0,4338
..........

pgbench=# select oid from pg_database where datname='pgbench';
  oid  
-------
 41029
(1 row)

pgbench=# select * from pg_tablespace where spcname='pg_default';
 oid  |  spcname   | spcowner | spcacl | spcoptions 
------+------------+----------+--------+------------
 1663 | pg_default |       10 |        | 
(1 row)

pgbench=# SELECT relfilenode FROM pg_class WHERE relname = 'pgbench_accounts';
 relfilenode 
-------------
       41042

下一步,我们将重新启动数据库,看看启动后,是否有预热功能。

pg_ctl stop 
pg_ctl start

2021-01-06 08:14:14.699 UTC [2947] LOG:  autoprewarm successfully prewarmed 16773 of 16773 previously-loaded blocks

重新启动后,您会发现日志中打印出一条的信息autoprewarm successfully prewarmed
,它表示预热成功。再次执行查询,可以看到全部数据都是shared hit。

相应的参数设置,pg_prewarm.autoprewarm
表示是否启动预热功能,pg_prewarm.autoprewarm_interval
表示进程将在多少秒内刷新一次至autoprewarm. blocks文件,默认情况下为300秒刷一次。

pgbench=# SELECT name, setting, unit FROM pg_settings WHERE name LIKE 'pg_prewarm%';
              name               | setting | unit 
---------------------------------+---------+------
 pg_prewarm.autoprewarm          | on      | 
 pg_prewarm.autoprewarm_interval | 300     | s
(2 rows)

最后还有两个重要的函数。

pgbench=# \df autoprewarm*
                                 List of functions
 Schema |           Name           | Result data type | Argument data types | Type 
--------+--------------------------+------------------+---------------------+------
 public | autoprewarm_dump_now     | bigint           |                     | func
 public | autoprewarm_start_worker | void             |                     | func
(2 rows)

  • autoprewarm_dump_now
     表示在服务器启动期间没有配置自动预热功能时,可以使用此命令启动自动预热工作程序。
  • autoprewarm_start_worker
    立马对 autoprewarm. blocks文件进行更新,如果自动预热进程当前没有运行,那么希望在下次重启之后运行它,这样做会很有用。

后记

pg_prewarm插件有一定的作用。在具体的使用场景中,我认为首先内存要足够大,其次,一些不经常使用的表(小表),但在查询时,需要较快的相应速度。如果是大表我觉得没必要,缓存大型表将减少可用来缓存任何其他数据的内存量,导致其他查询效率低下。而且数据库使用LRU算法,会将常用数据缓存在内存中。


文章转载自励志成为PostgreSQL大神,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论