pgpool-II 入门教程 [ 基于内存的查询缓存 ]

关于本文档

在本教程中,将讲解一个简单的方法来在共享内存中试用“基于内存的查询缓存”。

你需要的是一个安装有 PostgreSQL 和 pgpool-II 的 Linux 测试环境。你可以在任何模式中使用 基于内存的查询缓存:复制模式,主/备模式和原始模式。

基于内存的查询缓存

配置 pgpool.conf

基本参数

设置 "memory_cache_enabled" 为 on 以启用基于内存的查询缓存功能。

# If on, use the memory cache functionality, off by default
memory_cache_enabled = on

pgpool 会建立“OID 映射”文件,它用于指明哪个缓存用于哪个数据库和表。指定你希望用于这个用途的目录。

# Temporary work directory to record table oids
memqcache_oiddir = '/var/log/pgpool/oiddir'

关于共享内存

参数 "memqcache_method" 用于选择缓存的存储类型,默认为 "shmem"。

# Cache storage method. either 'shmem'(shared memory) or 'memcached'. 'shmem' by default
memqcache_method = 'shmem'

关于日志

参数 "log_per_node_statement" 可以帮助你了解某个查询是在哪个后端上执行。设置本参数为 on。

log_per_node_statement = on
                                   # Log all statements
                                   # with node and backend informations

启动 pgpool

使用 "-n" 参数(表示以非守护进程模式)启动 pgpool-II 并重定向日志消息到 pgpool.log 中。

$ {installed_dir}/bin/pgpool -n -f {installed_dir}/etc/pgpool.conf > pgpool.log 2>&1

建立数据库和表。

$ createdb -p 9999 test

$ psql -p 9999 test
test=> CREATE TABLE table_cache_ok (a INT);
CREATE TABLE

test=> INSERT INTO table_cache_ok VALUES (1), (2), (3);
INSERT 0 3

test=> SELECT * FROM table_cache_ok ORDER BY a;
 a
---
 1
 2
 3
(3 rows)

试用查询缓存

执行一个 SELECT 语句。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
 a
---
 1
(1 row)

log_per_node_statement 的输出显示 SELECT 语句被实际执行了。

LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

再次执行相同的 SELECT 语句。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
 a
---
 1
(1 row)

这次日志消息显示 SELECT 语句的结果来源于缓存。

LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

查询缓存的更多内容

自动失效

当一个表被更新

当一个表被更新,这个表中缓存的 SELECT 的结果会过期。 pgpool 默认情况下会自动忽略那个表上的所有缓存。

配置

通过 "memqcache_auto_cache_invalidation" 指定动作。它的默认值是 "on"。

# If on, invalidation of query cache is triggered by corresponding
# DDL/DML/DCL(and memqcache_expire).  If off, it is only triggered
# by memqcache_expire.  on by default.
memqcache_auto_cache_invalidation = on

修改这个参数的值后,重启 pgpool。

尝试自动失效的效果

确认你可以从缓存中获得 SELECT 语句的结果。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

在这个表中执行 INSERT INTO 。

test=> INSERT INTO table_cache_ok VALUES (5);
INSERT 0 1

再次执行相同的 SELECT 语句,这条 SELECT 语句被实际执行。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

缓存过期

pgpool 会忽略比指定过期周期更旧的缓存。

配置

通过 "memqcache_expire" 指定过期周期。默认为 0 秒,不过为了测试我们在这里设置为 5 秒。

# Memory cache entry life time specified in seconds.
# 0 means infinite life time. 0 by default.
memqcache_expire = 5

修改这个参数的值后,重启 pgpool。

Try

确认你可以从缓存中获得 SELECT 语句的结果。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

等 5 秒钟...

再次执行相同的 SELECT 语句,这条 SELECT 语句被实际执行。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

白名单和黑名单

只缓存某些表的结果

配置

如果你只想缓存某些表的结果,可以通过 "white_memqcache_table_list" 指定。

可以使用正则表达式(会自动添加 ^ 和 $)。

white_memqcache_table_list = '.*_cache_ok'
                                   # Comma separated list of table names to memcache
                                   # that don't write to database
                                   # Regexp are accepted

修改这个参数的值后,重新加载配置文件。

$ {installed_dir}/bin/pgpool reload

尝试

建立一个不需要缓存的表

$ psql -p 9999 test
test=> CREATE TABLE table_cache_ng (a INT);
CREATE TABLE

test=> INSERT INTO table_cache_ng VALUES (1), (2), (3);
INSERT 0 3

确认是否 SELECT FROM 在 white_memqcache_table_list 中的表被缓存。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT oid FROM pg_database WHERE datname = 'test'

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

确认是否 SELECT FROM 不在 white_memqcache_table_list 中的表不被缓存。

test=> SELECT * FROM table_cache_ng WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

test=> SELECT * FROM table_cache_ng WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

不缓存某些表的结果

Config

如果你不想缓存某些表的结果,可以通过 "black_memqcache_table_list" 指定。

可以使用正则表达式(会自动添加 ^ 和 $)。

black_memqcache_table_list = '.*_cache_ng'
                                   # Comma separated list of table names not to memcache
                                   # that don't write to database
                                   # Regexp are accepted

修改这个参数的值后,重新加载配置文件。

$ {installed_dir}/bin/pgpool reload

Try

确认是否 SELECT FROM 在 black_memqcache_table_list 中的表不被缓存。

test=> SELECT * FROM table_cache_ng WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

test=> SELECT * FROM table_cache_ng WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT * FROM table_cache_ok WHERE a = 1;

确认是否 SELECT FROM 不在 black_memqcache_table_list 中的表被缓存。

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 11203 statement: SELECT oid FROM pg_database WHERE datname = 'test'

test=> SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

还有什么内容?

太大的结果集

SELECT 的结果集的大小会受限于 "memqcache_maxcache"。

# Maximum SELECT result size in bytes.
# Must be smaller than memqcache_cache_block_size. Defaults to 400KB.
memqcache_maxcache = 409600

如果结果集大于 memqcache_maxcache,日志信息会告诉我们。 以下是一个示例,memqcache_maxcache 被设置为 1024 字节而 SELECT 出来的表的大小超过 10 MB。

LOG:   DB node id: 0 backend pid: 17749 statement: SELECT * FROM pgbench_accounts ;
LOG:   pool_add_temp_query_cache: data size exceeds memqcache_maxcache.
                                  current:983 requested:110 memq_maxcache:1024

指定某个查询不需要缓存

如果白名单和黑名单还不够用,可以在查询最开始的地方 put the text "/* NO QUERY CACHE */" at the head of the queries.

LOG:   statement: SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   query result fetched from cache. statement: SELECT * FROM table_cache_ok WHERE a = 1;

LOG:   statement: /* NO QUERY CACHE */ SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 18070 statement: /* NO QUERY CACHE */ SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   statement: /* NO QUERY CACHE */ SELECT * FROM table_cache_ok WHERE a = 1;
LOG:   DB node id: 0 backend pid: 18070 statement: /* NO QUERY CACHE */ SELECT * FROM table_cache_ok WHERE a = 1;

当然,这种方法需要修改你的程序。