如何在PostgreSQL中检查复制延迟?

44
我想使用PostgreSQL 9.3的流复制功能来测量将数据插入主表和从表之间的时间。为此,我创建了一个名为test_time的表,其中包含2个字段id(序列)和t(文本)。然后添加了一个触发器:

cur_time:=to_char(current_timestamp, 'HH12:MI:SS:MS:US'); update test_time set t=cur_time where id=new.id;

但两个表中的时间是相同的。我该如何测量延迟时间?


5
当然,时间是相同的。从主数据库复制到从数据库的数据是完全一致的副本。如果在传输到从数据库的过程中更改了数据,那就没有意义了。 - user330315
1
有没有其他方法来测量主表和从表之间的延迟时间? - Alf162
8个回答

42

Alf162在Craig Ringer的回答评论中提到了一个好的解决方案,所以我在这里进行澄清。

PostgreSQL有一个管理函数pg_last_xact_replay_timestamp(),它返回恢复期间重放的最后一个事务的时间戳。 这是主服务器上为该事务生成提交或中止WAL记录的时间。

因此,在副本上执行此查询select now()-pg_last_xact_replay_timestamp() as replication_lag将返回一个持续时间,表示当前时钟与从复制流应用的最后一个WAL记录的时间戳之间的时间差异。

请注意,如果主服务器未接收新的变更,则没有要流式传输的WAL记录,并且通过此方式计算的延迟将增长,而不会实际信号化复制延迟。如果主服务器几乎持续处于变更状态,它将不断流式传输WAL,并且上述查询是主服务器上更改出现在从服务器上的时间延迟的良好近似值。显然,系统时钟在两个主机上如何同步会影响准确性。


3
关于时钟同步的注释非常重要。如果没有运行NTP守护程序,则表示您可能没有相同的时钟。这帮助我解决了一个不断落后的从属问题,实际上只是时钟漂移。除了时间之外,查看您落后多少字节也很有用,以确保正常。 - Brian Ghidinelli
1
这个解决方案只适用于高度活跃的实例。如果您的数据库有不活动的时期,您将面临错误的负面影响。在我看来,依赖于 sent_lsnreplay_lsnwrite_lsn 是一个更好的选择。在 PG 的上下文中,时间的概念并不存在。 - vinni_f
@vinni_f 我认为我在原始答案中已经评论了需要活动才能使其工作。你提到的指标是在v10中引入的,在此答案最初编写时不可用。我建议您提交一个独立的答案,描述您使用它们的建议方法。 - dbenhur
另外,如果我们正在更新到v10,请参见下面的此答案,其中描述了现在可用的同步复制滞后度指标。 - dbenhur

28
您可以使用pg_xlog_location_diff比较主服务器的pg_current_xlog_insert_location和该后端的pg_stat_replication条目的replay_location,从而很容易地从主服务器端获取以字节为单位的延迟。
这仅适用于在主服务器上运行时。您无法从副本运行此操作,因为副本不知道主服务器领先了多少。
另外,这不会告诉您以为单位的延迟。在当前(至少在9.4版本中)的PostgreSQL版本中,没有与提交或WAL记录相关联的时间戳。因此,无法确定给定LSN(xlog位置)发生的时间有多久。
在当前的PostgreSQL版本中,获取副本延迟的唯一方法是定期向专用时间戳表提交update的外部进程。因此,您可以将副本上的current_timestamp与在副本上可见的最新条目的时间戳进行比较,以查看副本落后多少。这将创建额外的WAL流量,然后必须将其保留在您的归档WAL中以进行PITR(例如PgBarman),因此您应该平衡所需的滞后检测的粒度和增加的数据使用情况。
PostgreSQL 9.5可能会添加提交时间戳,这将有助于您找出给定提交发生多久以前以及因此副本落后于挂钟秒数多少。

8
谢谢。我使用pg_last_xact_replay_timestamp()解决了问题。 - Alf162
1
@Alf162 我应该知道那个。请将其发布为您自己的答案,如果您留下评论,我会点赞。 - Craig Ringer
即使您每100毫秒更新一次记录,从整体上看,这仍然不是很多的流量... - Volte
pg_stat_replication 视图现在包含副本滞后时间(write_lag、flush_lag、replay_lag):请参见 Vao 的答案:https://dev59.com/ZV4c5IYBdhLWcg3wFm84#46662612 - erwaman

16

如果您的数据库频繁进行写操作,那么下面的查询是一个接近获取从库滞后的近似值的方法。

select now() - pg_last_xact_replay_timestamp() AS replication_delay;

下面是一个更准确的查询,用于计算具有非常少写入的数据库的复制延迟。如果主服务器没有向从服务器发送任何写入,则pg_last_xact_replay_timestamp()可能保持不变,因此可能无法使用上述查询准确确定从库滞后。

SELECT CASE WHEN pg_last_xlog_receive_location() =
pg_last_xlog_replay_location() THEN 0 ELSE EXTRACT (EPOCH FROM now() -
pg_last_xact_replay_timestamp()) END AS log_delay;

12

PostgreSQL 10或更高版本(答案)

对于PostgreSQL 10或更高版本(函数pg_last_xlog_receive_location()等在此版本中不存在),我使用以下方法:

SELECT
  pg_is_in_recovery() AS is_slave,
  pg_last_wal_receive_lsn() AS receive,
  pg_last_wal_replay_lsn() AS replay,
  pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() AS synced,
  (
   EXTRACT(EPOCH FROM now()) -
   EXTRACT(EPOCH FROM pg_last_xact_replay_timestamp())
  )::int AS lag;

如果在主节点上运行此查询,则结果将如下所示:

 is_slave | receive | replay | synced | lag 
----------+---------+--------+--------+-----
 f        |         |        |        |    
(1 row)

如果你在同步从库上运行此查询,结果将如下:

 is_slave |  receive  |  replay   | synced | lag 
----------+-----------+-----------+--------+-----
 t        | 0/3003128 | 0/3003128 | t      | 214
(1 row)

如果您在未同步的从服务器上运行此查询,则结果将如下所示:

 is_slave |  receive  |  replay   | synced | lag 
----------+-----------+-----------+--------+-----
 t        | 0/30030F0 | 0/30023B0 | f      | 129
(1 row)

注意: 这里的lag(秒)有一个特殊的含义(与来自pg_stat_replication视图的replay_lag/write_lag/flush_lag不同),它仅在synced列为false时才有用,因为lag表示自上次操作提交以来经过了多少秒。 在低流量的网站中,此值是无用的。 但是在高流量的网站中,synced几乎总是false,但是如果它具有足够小的lag值,则可以认为该服务器已同步。

因此,为了发现该服务器是否已同步,我按以下顺序检查:

  • IF is_slavef(表示不是从属服务器,可能是主服务器,因此已同步);
  • IF syncedt(表示已同步的从属服务器,因此已同步);
  • IF(假设适用)lag <= :threshold:(表示不是已同步的从属服务器,但距离主服务器不太远,因此对我来说已获得同步状态)。

如果您想要包括小数秒的延迟,请执行以下操作:

SELECT
  pg_is_in_recovery() AS is_slave,
  pg_last_wal_receive_lsn() AS receive,
  pg_last_wal_replay_lsn() AS replay,
  pg_last_wal_receive_lsn() = pg_last_wal_replay_lsn() AS synced,
  EXTRACT(SECONDS FROM now() - pg_last_xact_replay_timestamp())::float AS lag;

8

稍微不同的正确答案版本:

postgres=# SELECT
  pg_last_xlog_receive_location() receive,
  pg_last_xlog_replay_location() replay,
  (
   extract(epoch FROM now()) -
   extract(epoch FROM pg_last_xact_replay_timestamp())
  )::int lag;

  receive   |   replay   |  lag  
------------+------------+-------
 1/AB861728 | 1/AB861728 | 2027

当“接收”不等于“回复”时,延迟只有很重要。在副本上执行查询。


这应该在主节点还是从节点上运行?(我猜是从节点,但请在答案中确认)。 - ypercubeᵀᴹ
由于您正在请求接收日志,因此在从机上。 - Gaetano Mendola

8

截至10版:

https://www.postgresql.org/docs/10/static/monitoring-stats.html#pg-stat-replication-view

write_lag 间隔时间 本地刷新最近的WAL并接收到此备用服务器已写入但尚未刷新或应用的通知之间经过的时间。如果此服务器被配置为同步备用,则可以使用此项来衡量在提交时synchronous_commit级别remote_write所引起的延迟。

flush_lag 间隔时间 本地刷新最近的WAL并接收到此备用服务器已写入和刷新但尚未应用的通知之间经过的时间。如果此服务器被配置为同步备用,则可以使用此项来衡量在提交时synchronous_commit级别remote_flush所引起的延迟。

replay_lag 间隔时间 本地刷新最近的WAL并接收到此备用服务器已写入、刷新和应用的通知之间经过的时间。如果此服务器被配置为同步备用,则可以使用此项来衡量在提交时synchronous_commit级别remote_apply所引起的延迟。

(格式由我调整)

不幸的是,新列似乎只适用于同步复制(否则主服务器将不知道确切的延迟),因此异步复制延迟检查似乎仍为now()-pg_last_xact_replay_timestamp()...


帖子主题没有指定同步类型,因此我认为上面的信息可能会帮助某人在这里找到它。 - Vao Tsun

1

您可以使用这个简单的基于CLI的开源工具,它可以提供实时可视化关于复制延迟的信息,使用各种模式,例如CLI、Web模式以及基于Matplotlib的图表,方便跟踪。

复制延迟可视化工具

欢迎提出任何问题或为其做出贡献。

Web Mode


0
在主服务器上,您可以执行 select * from pg_stat_replication; 这将给您以下结果:
|  sent_lsn   |  write_lsn  |  flush_lsn  | replay_lsn  

-+-------------+-------------+-------------+-------------

 | 8D/2DA48000 | 8D/2DA48000 | 8D/2DA48000 | 89/56A0D500 

这些可以告诉您偏移量的位置。正如您从此示例中看到的那样,副本上的回放落后了。


1
PostgreSQL 9.3中的pg_stat_replication没有这些列,而这正是此问题明确要求的内容。 - eric.green

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接