预写日志 + 了解checkpoint参数

发布时间 2023-11-25 19:21:34作者: jl1771

在执行大量写操作的系统上,调优检查点对于获得良好的性能至关重要。然而,检查点是我们经常发现混淆和配置问题的地方之一,那么让我带你了解一下检查点,它们做什么以及如何在PostgreSQL中调优它们。

虽然有一些关于它的文档,但我决定用可能更容易理解的语言来写它——不是作为开发人员,而是作为 PostgreSQL 用户。

我之前的一篇文章中描述了一些部分(相当大的部分),但我会尝试专注于 WAL 本身,并在这里展示更多内容。

在我讨论它是如何编写以及如何检查各种事物之前,首先让我们尝试思考一个简单的问题:为什么这样的东西会存在?它有什么作用?

假设您有一个 1GB 的文件,并且您想要从某个定义的偏移量更改其中的 100kB。

理论上它很简单 – 打开要写入的文件(不覆盖),执行fseek()到适当的位置,然后写入新的 100kB。然后关闭文件,打开一杯啤酒——工作完成。

但真的是这样吗?如果写入时断电会发生什么?你没有 UPS 吗?

这实际上是非常糟糕的情况 - 让我们假设它发生在流程中间。你的程序被杀死了(好吧,机器被关闭了),磁盘上的数据包含一半旧数据和一半新数据!

当然,您可能会说这就是我们拥有 UPS 的原因,但现实有点复杂 – 各种磁盘或存储控制器都有写缓存,并且可以向操作系统(然后向应用程序撒谎)谎称数据已写入,而它在缓存中,然后问题可能会再次出现。

因此,必须找到解决方案,确保我们要么拥有新数据,要么拥有旧数据,但不能混合使用。

这里的解决方案相对简单。除了这个 1GB 数据文件之外,还存储其他文件,这些文件永远不会被覆盖,只会被附加。并将您的流程更改为:

  • 以附加模式打开日志文件
  • 写入日志文件信息“将在偏移量(offset)处将此数据(此处为数据)写入此文件(路径)”
  • 关闭日志文件
  • 确保日志文件实际写入磁盘。调用fsync()并希望磁盘能够正确执行
  • 正常更改数据文件
  • 将日志文件中的操作标记为已完成

最后一部分可以通过将日志文件中最后应用的更改存储在某个位置来简单地完成。

现在。让我们考虑一下电源故障。如果写入日志文件时突然断电怎么办?没有什么。真实文件中的数据没有被损坏,并且您的程序必须足够聪明才能忽略未完全写入的日志条目。如果在更改真实文件中的数据时发生断电,会发生什么情况?这很简单 - 在程序下次启动时,您检查日志中是否有任何应该应用但没有应用的更改,然后应用它们 - 当程序启动时,数据文件的内容被破坏,但它会很快修复。

标记操作完成时是否会断电?没问题——下次启动时,操作将被简单地重做。

多亏了这一点,我们(相当)免受此类事情的影响。它还具有其他好处,但这将在稍后实现。

所以,现在我们知道了 WAL 的目的是什么(如果还不清楚:保护您的数据免受硬件/电源故障的影响),让我们考虑一下如何做。

PostgreSQL 使用所谓的“页面”。除了页面之外的所有内容只是 8kB 的数据。这就是为什么表/索引文件的大小始终可以被 8192 (8kB) 整除 - 你不能拥有 10.5 页大小的表。它有 11 页.并非所有页面都已满。甚至并非所有页面都保证可以使用(它们可能包含已删除的数据)。

所有IO操作都使用页面。即为了从表中获取 INT4 值,PostgreSQL 读取 8kB 的数据(至少)。

那么,当您插入新行时会发生什么?首先 PostgreSQL 找到它将把它放到哪个页面。如果表的所有页面都已满,则它可能是新创建的页面,或者如果其中有可用空间,则它可能是其他页面。

选择页面后,PostgreSQL 将其加载到内存(shared_buffers),并在那里进行更改。所有更改的信息都会记录到 WAL,但这是通过简单的“write()”完成的(尚未调用 fsync),因此速度非常快。

现在,当您发出 COMMIT 时;(如果是自动提交连接,这可能会自动发生),PostgreSQL 实际上对 WAL 执行 fsync()。就这样。数据不会写入您的表文件。

此时,您想要的更改(新行)位于 2 个位置:

  • 修改了shared_buffers中表页的副本
  • 在 WAL 中记录有关更改的信息

所有对 WAL 的写入都不是由单独的后端完成的,而是由专门的进程——wal writer 完成的,您可以在这里看到:

=$ ps uxf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
pgdba    25473  0.0  0.0 112552  2104 ?        S    01:16   0:00 sshd: pgdba@pts/8
pgdba    25474  0.0  0.0  28000  6704 pts/8    Ss   01:16   0:00  \_ -bash
pgdba    25524  0.0  0.0  20520  1148 pts/8    R+   01:16   0:00      \_ ps uxf
pgdba     7366  0.0  0.0  67716  7492 ?        S    Jul13   0:00 /home/pgdba/work/bin/postgres
pgdba     7368  0.0  0.0  25308   888 ?        Ss   Jul13   0:01  \_ postgres: logger process
pgdba     7370  0.5  0.2  67936 36176 ?        Ss   Jul13   0:55  \_ postgres: writer process
pgdba     7371  0.0  0.0  67716  2072 ?        Ss   Jul13   0:08  \_ postgres: wal writer process
pgdba     7372  0.0  0.0  68824  5588 ?        Ss   Jul13   0:00  \_ postgres: autovacuum launcher process
pgdba     7373  0.0  0.0  27404   900 ?        Ss   Jul13   0:00  \_ postgres: archiver process   last was 000000010000000800000057
pgdba     7374  0.0  0.0  27816  1340 ?        Ss   Jul13   0:01  \_ postgres: stats collector process

因此,对 WAL 的写入没有锁定,只是简单的数据追加。

现在,如果我们继续这个过程很长时间,我们就会在内存中拥有大量修改过的页面,并在 WAL 中拥有大量记录。

那么,数据什么时候写入表的实际磁盘页呢?

两种情况:

  • 页面交换
  • checkpoint

页面交换是非常简单的过程——假设我们将shared_buffers 设置为10,并且所有这些缓冲区都被10 个不同的页面占用,并且全部都被修改。现在,由于用户活动,PostgreSQL 必须加载另一个页面才能从中获取数据。会发生什么?很简单——其中一页将从内存中逐出,然后加载新页面。如果被删除的页面是“脏”的(这意味着其中有一些尚未保存到表文件的更改),它将首先写入表文件。

检查点更有趣。在我们讨论它是什么之前,让我们先考虑一下理论场景。您的数据库大小为 1GB,服务器有 10GB RAM。显然,您可以将数据库的所有页面保留在内存中,因此页面交换永远不会发生。

如果让数据库长时间运行、写入、更改、添加,会发生什么情况?理论上一切都会好起来的——所有的改变都会被记录到 WAL 中,内存页面也会被修改,一切都很好。现在想象一下,工作 24 小时后,系统再次死机——电源故障。

下次启动时,PostgreSQL 必须读取并应用过去 24 小时内发生的所有 WAL 段的所有更改!这是一项繁重的工作,这会导致 PostgreSQL 的启动花费很长的时间。

为了解决这个问题,我们设置了检查点。这些通常会自动发生,但您可以通过发出CHECKPOINT命令强制它们随意发生。

那么,什么是检查点?Checkpoint 做了非常简单的事情:它将所有脏页从内存写入磁盘,在共享缓冲区中将它们标记为“干净”,并存储到目前为止所有 wal 都已应用的信息。当然,这是在没有任何锁定的情况下发生的。因此,立即执行从这里得到的信息是,新启动的 PostgreSQL 必须做的工作量与最后一个 CHECKPOINT 之前经过的时间以及 PostgreSQL 停止的时刻有关。

这让我们回到——当它发生的时候。手动检查点并不常见,通常人们甚至不会考虑它 - 这一切都发生在后台。那么 PostgreSQL 如何知道何时进行检查点呢?很简单,这要归功于两个配置参数:

  • checkpoint_segments
  • checkpoint_timeout

在这里,我们必须了解一些有关细分的知识。

正如我之前写的——WAL(理论上)是无限文件,它只获取新数据(附加),并且永远不会覆盖。

虽然这在理论上很好,但实践有点复杂。例如,在最后一个检查点之前记录的 WAL 数据实际上没有任何用处。并且无限大小的文件是不可能的(至少目前是这样)。

PostgreSQL 开发人员决定将这个无限 WAL 分段。每个段都有其连续的编号,大小为 16MB。当一个段已满时,PostgreSQL 只需切换到下一个段。

现在,我们知道什么是段,我们就可以理解 checkpoint_segments 的含义了。这是数字(默认值:3),这意味着:如果自上一个检查点以来已填充了那么多段,则发出新的检查点。

使用默认值,这意味着如果您插入需要(以 PostgreSQL 格式)6144 页的数据(16MB 的段是 2048 页,因此 3 个段是 6144 页)——它将自动发出检查点。

第二个参数 – checkpoint_timeout,是一个时间间隔(默认为 5 分钟),如果这个时间从上一个检查点过去 – 将发出新的检查点。必须理解的是,(通常)设置检查点的次数越多,它们的侵入性就越小。

这来自一个简单的事实——通常,随着时间的推移,越来越多的不同页面会变。如果您每分钟检查一次,则只需将分钟内的页面写入磁盘。5 分钟 – 更多页面。1 小时——甚至更多页。

虽然检查点不会锁定任何内容,但必须了解(例如)30 个段的检查点将导致 480 MB 数据高强度写入磁盘。这可能会导致并发读取速度减慢。

到目前为止,我希望情况已经很清楚了。

现在,拼图的下一部分—— wal segments.

这些文件(wal 段)驻留在 PostgreSQL PGDATA 的 pg_xlog/ 目录中:

=$ ls -l data/pg_xlog/
total 131076
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:39 000000010000000800000058
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:03 000000010000000800000059
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:03 00000001000000080000005A
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005B
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005C
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005D
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:06 00000001000000080000005E
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:06 00000001000000080000005F
drwx------ 2 pgdba pgdba     4096 2011-07-14 01:14 archive_status/

每个段名称包含 3 个 8 个十六进制数字块。例如:00000001000000080000005C表示:

  • 00000001 – 时间线 1
  • 00000008 – 第 8 个区块
  • 0000005C – 块内的十六进制(5C)段

最后一部分仅从 00000000 到 000000FE(不是 FF!)——直到 PostgreSQL 9.2。从9.3一直到FF。

文件名的第二部分加上第三部分末尾的 2 个字符给我们的位置是这个理论上的无限 WAL 文件。

在 PostgreSQL 中我们总是可以检查当前的 WAL 位置:

$ SELECT pg_current_xlog_location();
 pg_current_xlog_location
--------------------------
 8/584A62E0
(1 ROW)

这意味着我们现在使用文件 xxxxxxxx000000080000058,并且 PostgreSQL 在其中的偏移量 4A62E0 处写入 – 即 4874976,由于 WAL 段是 16MB,这意味着 wal 段现在已填充约 25%。

最神秘的是时间线。时间线从1开始,每次你从服务器上做WAL-slave时,时间线就会增加(一个),这个Slave就会升级为独立的。一般来说,在给定的工作服务器中,这个值不会改变。

所有这些信息我们也可以使用 pg_controldata 程序获得:

=$ pg_controldata data
pg_control version number:            903
Catalog version number:               201107031
Database system identifier:           5628532665370989219
Database cluster state:               in production
pg_control last modified:             Thu 14 Jul 2011 01:49:12 AM CEST
Latest checkpoint location:           8/584A6318
Prior checkpoint location:            8/584A6288
Latest checkpoint's REDO location:    8/584A62E0
Latest checkpoint's TimeLineID:       1
Latest checkpoint's NextXID:          0/33611
Latest checkpoint's NextOID:          28047
Latest checkpoint's NextMultiXactId:  1
Latest checkpoint's NextMultiOffset:  0
Latest checkpoint's oldestXID:        727
Latest checkpoint's oldestXID's DB:   1
Latest checkpoint's oldestActiveXID:  33611
Time of latest checkpoint:            Thu 14 Jul 2011 01:49:12 AM CEST
Minimum recovery ending location:     0/0
Backup start location:                0/0
Current wal_level setting:            hot_standby
Current max_connections setting:      100
Current max_prepared_xacts setting:   0
Current max_locks_per_xact setting:   64
Maximum data alignment:               8
Database block size:                  8192
Blocks per segment of large relation: 131072
WAL block size:                       8192
Bytes per WAL segment:                16777216
Maximum length of identifiers:        64
Maximum columns in an index:          32
Maximum size of a TOAST chunk:        1996
Date/time type storage:               64-bit integers
Float4 argument passing:              by value
Float8 argument passing:              by value

这有一些有趣的信息——例如最后一个检查点、前一个检查点的位置(在 WAL 无限文件中)和 REDO 位置。

REDO 位置非常重要——这是 WAL 中的位置,如果 PostgreSQL 被杀死并重新启动,则必须从中读取

上面的值差别不大,因为这是我的测试系统,现在没有任何流量,但我们可以在另一台机器上看到:

=> pg_controldata data/
...
Latest checkpoint location:           623C/E07AC698
Prior checkpoint location:            623C/DDD73588
Latest checkpoint's REDO location:    623C/DE0915B0
...

最后一件重要的事情是了解过时的 WAL 段会发生什么,以及如何创建“新”的 wal 段。

让我再告诉你一件事:

=$ ls -l data/pg_xlog/
total 131076
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:39 000000010000000800000058
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:03 000000010000000800000059
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:03 00000001000000080000005A
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005B
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005C
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:04 00000001000000080000005D
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:06 00000001000000080000005E
-rw------- 1 pgdba pgdba 16777216 2011-07-14 01:06 00000001000000080000005F
drwx------ 2 pgdba pgdba     4096 2011-07-14 01:14 archive_status/

这是在没有写入的系统上,REDO 位置为 8/584A62E0。

由于启动时 PostgreSQL 需要从此位置读取,因此 000000010000000800000058 之前的所有 WAL 段(即 000000010000000800000057、000000010000000800000056 等)都已过时。

另一方面 - 请注意,我们准备了七个文件供将来使用。

PostgreSQL 以这种方式工作:每当 WAL 段过时(即 REDO 位置在 WAL 中比该段晚)时,文件就会被重命名。这是正确的。不是删除了,是改名了。改成什么?到 WAL 中的下一个文件。因此,当我进行一些写入操作时,8/59* 位置将出现检查点,文件 000000010000000800000058 将被重命名为 000000010000000800000060。

这就是为什么你的 checkpoint_segments 不应该太低的原因之一。

让我们想一下,如果 checkpoint_timeout 很长,并且我们会填充所有 checkpoint_segments 会发生什么。要记录新的写入,PostgreSQL 必须执行检查点(它将执行),但同时 – 它不会再有任何可用的就绪段。所以它必须创建新文件。16MB 数据(可能是 \x00)——必须先将其写入磁盘,然后PostgreSQL 才能写入用户请求的任何内容。这意味着,如果达到 checkpoint_segments,并发用户活动将会减慢,因为 PostgreSQL 必须创建新文件来容纳用户请求的数据写入。

通常这不是问题,您只需将 checkpoint_segments 设置为某个相对较高的数字即可。

无论如何。在查看pg_xlog/目录时,当前的WAL段(获取写的那个)通常处于中间的某个位置。这可能会引起一些混乱,因为文件的mtime不会与文件名中的数字在同一个方向上改变。像在这里:

$ ls -l
total 704512
-rw------- 1 postgres postgres 16777216 Jul 13 16:51 000000010000002B0000002A
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B0000002B
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B0000002C
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B0000002D
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B0000002E
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B0000002F
-rw------- 1 postgres postgres 16777216 Jul 13 16:55 000000010000002B00000030
-rw------- 1 postgres postgres 16777216 Jul 13 17:01 000000010000002B00000031
-rw------- 1 postgres postgres 16777216 Jul 13 17:16 000000010000002B00000032
-rw------- 1 postgres postgres 16777216 Jul 13 17:21 000000010000002B00000033
-rw------- 1 postgres postgres 16777216 Jul 13 14:31 000000010000002B00000034
-rw------- 1 postgres postgres 16777216 Jul 13 14:32 000000010000002B00000035
-rw------- 1 postgres postgres 16777216 Jul 13 14:19 000000010000002B00000036
-rw------- 1 postgres postgres 16777216 Jul 13 14:36 000000010000002B00000037
-rw------- 1 postgres postgres 16777216 Jul 13 14:37 000000010000002B00000038
-rw------- 1 postgres postgres 16777216 Jul 13 14:38 000000010000002B00000039
-rw------- 1 postgres postgres 16777216 Jul 13 14:39 000000010000002B0000003A
-rw------- 1 postgres postgres 16777216 Jul 13 14:40 000000010000002B0000003B
-rw------- 1 postgres postgres 16777216 Jul 13 14:41 000000010000002B0000003C
-rw------- 1 postgres postgres 16777216 Jul 13 14:41 000000010000002B0000003D
-rw------- 1 postgres postgres 16777216 Jul 13 14:42 000000010000002B0000003E
-rw------- 1 postgres postgres 16777216 Jul 13 14:43 000000010000002B0000003F
-rw------- 1 postgres postgres 16777216 Jul 13 14:33 000000010000002B00000040
-rw------- 1 postgres postgres 16777216 Jul 13 14:34 000000010000002B00000041
-rw------- 1 postgres postgres 16777216 Jul 13 14:45 000000010000002B00000042
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000043
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000044
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000045
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000046
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000047
-rw------- 1 postgres postgres 16777216 Jul 13 14:55 000000010000002B00000048
-rw------- 1 postgres postgres 16777216 Jul 13 15:09 000000010000002B00000049
-rw------- 1 postgres postgres 16777216 Jul 13 15:25 000000010000002B0000004A
-rw------- 1 postgres postgres 16777216 Jul 13 15:35 000000010000002B0000004B
-rw------- 1 postgres postgres 16777216 Jul 13 15:51 000000010000002B0000004C
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B0000004D
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B0000004E
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B0000004F
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B00000050
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B00000051
-rw------- 1 postgres postgres 16777216 Jul 13 15:55 000000010000002B00000052
-rw------- 1 postgres postgres 16777216 Jul 13 16:19 000000010000002B00000053
-rw------- 1 postgres postgres 16777216 Jul 13 16:35 000000010000002B00000054
drwx------ 2 postgres postgres       96 Jun  4 23:28 archive_status

请注意,最新文件 – 000000010000002B00000033 既不是第一个,也不是最后一个。最旧的文件 - 在最新的文件之后引用 - 000000010000002B00000036。

这都是自然的。当前之前的所有文件都是仍然需要的文件,并且它们的 mtime 将与 WAL 段编号的方向相同。

最后一个文件(基于文件名) - *54 在 *2A 之前有 mtime - 这告诉我们它以前是 *29,但当 REDO 位置移动到文件 *2A 的某个位置时被重命名。

希望上面的解释已经清楚,如果还不清楚,请在评论中说明您的问题/疑虑。

总结一下。WAL的存在是为了在紧急情况下拯救你。由于WAL,很难得到任何数据问题-我甚至可以说是不可能的,但在你的硬件出错的情况下仍然是可能的-例如:关于实际磁盘写入的谎言。

WAL 存储在 pg_xlog/ 目录中的多个文件中,并且这些文件会被重用,因此该目录不应增长。这些文件的数量通常是2 * checkpoint_segments + 1

为什么是 2* checkpoint_segments?

原因很简单。假设您将 checkpoint_segments 设置为 5。您已将它们全部填充,并调用 checkpoint。检查点在 WAL 段 #x 中调用。在 #x + 5 中我们将有另一个检查点。但 PostgreSQL 总是(至少)将 checkpoint_segments 保持在当前位置之前,以避免需要为用户查询的数据创建新的段。因此,在任何特定时刻,您可能会:

  • 当前段
  • checkpoint_segments 段,因为 REDO 位置
  • checkpoint_segments 当前位置前面的“缓冲区”

有时,当您的写入次数多于 checkpoint_segments 时,在这种情况下 PostgreSQL 将创建新段(如上所述)。这会增加 pg_xlog/ 中的文件数量。但这会在一段时间后恢复 - 只是一些过时的段不会被重命名,而是会被删除。

最后,最后一件事。GUC“checkpoint_warning”。它也有(像 checkpoint_timeout 一样)间隔,通常要短得多 – 默认为 30 秒。如果自动检查点发生得太频繁,这用于记录(不是 WAL,而是正常日志)信息。

由于 checkpoint_timeout 应该大于 checkpoint_warning,这通常意味着如果您在 checkpoint_timeout 时间内填充的日志数量超过 checkpoint_segments ,它就会发出警报。

此类信息如下所示:

2011-07-14 01:03:22.160 CEST @ 7370 LOG: checkpoint starting: xlog
2011-07-14 01:03:26.175 CEST @ 7370 LOG: checkpoint complete: wrote 1666 buffers (40.7%); 0 transaction log file(s) added, 0 removed, 3 recycled; write=3.225 s, sync=0.720 s, total=4.014 s; sync files=5, longest=0.292 s, average=0.144 s
2011-07-14 01:03:34.904 CEST @ 7370 LOG: checkpoints are occurring too frequently (12 seconds apart)
2011-07-14 01:03:34.904 CEST @ 7370 HINT: Consider increasing the configuration parameter "checkpoint_segments".
2011-07-14 01:03:34.904 CEST @ 7370 LOG: checkpoint starting: xlog
2011-07-14 01:03:39.239 CEST @ 7370 LOG: checkpoint complete: wrote 1686 buffers (41.2%); 0 transaction log file(s) added, 0 removed, 3 recycled; write=3.425 s, sync=0.839 s, total=4.334 s; sync files=5, longest=0.267 s, average=0.167 s
2011-07-14 01:03:48.077 CEST @ 7370 LOG: checkpoints are occurring too frequently (14 seconds apart)
2011-07-14 01:03:48.077 CEST @ 7370 HINT: Consider increasing the configuration parameter "checkpoint_segments".
2011-07-14 01:03:48.077 CEST @ 7370 LOG: checkpoint starting: xlog

请注意“HINT”行。

这些只是提示(不是警告或致命错误),因为太低的 checkpoint_segments 不会对您的数据造成任何风险 - 它只是可能会减慢与客户端的交互,如果用户将发送修改查询,则必须等待新的查询要创建的 WAL 段(即写入磁盘的 16MB)。

最后一点 - 如果您对 PostgreSQL 进行某种监控(例如cactigangliamunin或一些商业广告,例如circonus),您可能需要添加图表来及时显示您的 WAL 进度。

为此,您需要将当前 xlog 位置转换为某个正常的十进制数,然后绘制差异。例如这样:

=$ psql -qAtX -c "select pg_current_xlog_location()" | \
    awk -F/ 'BEGIN{print "ibase=16"} {printf "%s%08s\n", $1, $2}' | \
    bc
108018127223360

或者,如果数字太大,则仅使用文件的十进制“数字”:

=$ (
    echo "ibase=16"
    psql -qAtX -c "select pg_xlogfile_name(pg_current_xlog_location())" | \
        cut -b 9-16,23-24
) | bc
6438394

以 5 分钟为增量绘制第二个值 (6438394) 的增量将告诉您最佳 checkpoint_segments 是什么(尽管始终记住使其比实际需要的稍大一些,以防流量突然激增)。