段落引用原文作者: Hans-Jürgen Schönig
翻译:Tracy
原文链接:https://www.cybertec-postgresql.com/en/checkpoint-distance-and-amount-of-wal
大多数使用 PostgreSQL 数据库系统的人都知道,数据库引擎必须将更改发送到所谓的“预写式日志”(Write Ahead Log, = WAL),确保在发生崩溃时数据库能够恢复到一致状态,以保证数据库的安全可靠。然而,并不是每个人都知道调整数据库服务器实际上会对必须写入磁盘的WAL日志的数量产生影响。
WAL日志和检查点
在 PostgreSQL 中,必须先将更改写入 WAL日志(或某些人称之为 xlog),然后才能将这些更改写入底层数据文件。在大多数情况下,PostgreSQL 会简单地向WAL日志中记录数据文件中必须更改的内容,然而,有时还需要记录比写到数据文件的数据更多的内容。
为了确保WAL不会无限增长,PostgreSQL会做被称为检查点的操作,这是回收WAL日志的绝佳机会。数据库事务大小应该或多或少保持不变,因此不时清理 WAL 是绝对必须的。幸运的是,检查点是自动完成的。
默认情况下,PostgreSQL 使用以下参数来确定何时应该发生检查点:
# checkpoint_timeout = 5min # 范围 30s-1h
# max_wal_size = 1GB
# min_wal_size = 80MB
这些默认设置对于一个合理的小型数据库来说是可以的。然而,对于一个大系统来说,减少检查点将有助于提高性能。如果您的系统相当大且负载很重(写入),那么将 max_wal_size 设置为 20GB 绝对是一件好事。
众所周知的是,增加检查点的距离不仅会提高速度——更少的检查点还会对写入的事务日志量产生影响。
减少写入的事务日志量
增加检查点之间的距离会导致WAL日志减少——但为什么会发生这种情况呢?请记住:首先记录事务日志的全部意义在于确保系统在崩溃时始终能成功恢复。将 WAL日志中的这些更改应用于数据文件将修复数据文件并在启动时恢复系统。为了安全地做到这一点,PostgreSQL 不能简单地记录对块所做的更改——如果块在检查点后第一次被更改,则必须将整个页面记录到 WAL日志中。所有后续更改都可以是增量的。现在的重点是:如果检查点靠得很近,则有很多“第一次”,并且必须非常频繁地将整页写入 WAL日志。但是,如果检查点相距很远,整页写入的数量将急剧下降,从而导致WAL日志量大大减少。
在重载系统上,我们并不是在谈论微不足道的东西——差别可能是相当显著的。
测量 WAL 写入量
为了测量系统在正常基准测试期间实际产生了多少事务日志,我使用空数据库实例进行了一个简单的测试:
[hs@linuxpc db]$ createdb test [hs@linuxpc db]$ psql test psql (9.6.1) Type "help" for help.
为了减少磁盘刷新次数并让我的SSD磁盘拥有长久的寿命,我将 synchronous_commit 设置为 off:
test=# ALTER DATABASE test SET synchronous_commit TO off;
ALTER DATABASE
然后加载一小组测试数据:
[hs@linuxpc db]$ pgbench -i test NOTICE: table "pgbench_history" does not exist, skipping NOTICE: table "pgbench_tellers" does not exist, skipping NOTICE: table "pgbench_accounts" does not exist, skipping NOTICE: table "pgbench_branches" does not exist, skipping creating tables... 100000 of 100000 tuples (100%) done (elapsed 0.09 s, remaining 0.00 s) vacuum... set primary keys... done.
100,000 行绝对足以进行这个简单的测试。
然后 4 个并发连接每个将执行 200 万个事务。对于第一个测试,使用默认的 PostgreSQL 配置参数:
[hs@linuxpc db]$ time pgbench -c 4 -t 2000000 test starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 4 number of threads: 1 number of transactions per client: 2000000 number of transactions actually processed: 8000000/8000000 latency average = 0.558 ms tps = 7173.597623 (including connections establishing) tps = 7173.616874 (excluding connections establishing) real 18m35.222s user 2m23.980s sys 3m4.830s
生成的 WAL 量约为 3.5 GB:
test=# SELECT pg_size_pretty(pg_current_xlog_location() - '0/00000000'::pg_lsn);
pg_size_pretty
----------------
3447 MB
(1 row)
但是,如果检查点距离急剧减小会怎样?
checkpoint_timeout = 30s max_wal_size = 32MB min_wal_size = 32MB
WAL 的数量将猛增,因为检查点非常接近,以至于大多数更改将是对块进行的“第一次更改”。使用这些参数,WAL 将飙升至惊人的 23 GB。如您所见,如果这些设置不理想,WAL 的数量很容易成倍增加。
增加检查点之间的距离肯定会加快速度并对WAL日志量产生积极影响:





