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

Posted

技术标签:

【中文标题】如何检查 PostgreSQL 中的复制延迟?【英文标题】:How to check the replication delay in PostgreSQL? 【发布时间】:2015-04-04 02:11:58 【问题描述】:

我想在 PostgreSQL 9.3 中使用流复制来测量将数据插入主表和从表之间的时间。为此,我创建了具有 2 个字段 id(serial)、t(text) 的表 test_time。之后添加了一个触发器:

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

但是两张表的时间是一样的。 如何测量延迟时间

【问题讨论】:

是的,当然时间是一样的。从站上的数据是主站的 100% 相同副本。如果数据在发送到从站的途中发生更改,那将没有任何意义。 还有其他方法可以测量主从表之间的延迟时间吗? 【参考方案1】:

Alf162 在 Craig Ringer 的回答中提到了 cmets 中的一个很好的解决方案;所以我添加这个来澄清一下。

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

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

请注意,如果主节点没有接收到新的突变,则不会有 WAL 记录可供流式传输,并且以这种方式计算的延迟将会增加,而实际上并不是复制延迟的信号。如果主节点或多或少处于连续突变状态,它将持续流式传输 WAL,并且上述查询是对主节点上的更改在从节点上实现的时间延迟的精细近似。精度显然会受到两台主机上系统时钟同步的严格程度的影响。

【讨论】:

关于时钟同步的注释非常重要。没有运行 NTP 守护程序意味着您可能没有相同的时钟。这只是帮助我解决了一个稳步下降的奴隶问题,事实上,这只是时钟漂移。作为健全性检查,除了时间之外,查看您落后多少字节很有用。 此解决方案仅适用于高度活跃的实例。如果您的数据库中有一段时间不活跃,您将面临误报。 IMO 依赖 sent_lsnreplay_lsnwrite_lsn 是更好的选择。时间的概念不是 PG 范畴内的东西。 @vinni_f 我想我评论说需要活动才能在原始答案中完成这项工作。您提到的指标是在 v10 中引入的,在最初编写此答案时不可用。我建议您提交一个独立的答案,描述您使用它们的建议方法。 另外,如果我们正在更新 v10,请参阅 this answer below 描述现在可用的同步复制滞后指标。【参考方案2】:

您可以使用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 可能会添加提交时间戳,有望让您了解给定提交发生了多长时间,以及副本在挂钟秒内落后了多长时间。

【讨论】:

谢谢。我解决了问题,使用 pg_last_xact_replay_timestamp(); @Alf162 我应该知道的。请将其发布为您自己的答案,如果您给我发表评论,我会投票赞成。 即使你每 100 毫秒更新一次记录,从总体上看,这仍然不是很多流量...... pg_stat_replication 视图现在包含副本滞后作为时间(write_lag、flush_lag、replay_lag):请参阅下面 Vao 的回答:***.com/a/46662612/1128392【参考方案3】:

如果您的数据库频繁写入,则以下查询是获取从属延迟的近似值

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;

【讨论】:

【参考方案4】:

正确答案的版本略有不同:

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

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

【讨论】:

这个应该在master还是slave上运行? (我猜是奴隶,但请在答案中添加)。 在奴隶上,因为您正在询问收到的日志。【参考方案5】:

截至 10 版:

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

write_lag interval 从本地刷新最近的 WAL 到接收到此备用服务器有通知之间经过的时间 写了它(但尚未刷新或应用它)。这可以用来 衡量 synchronous_commit 级别 remote_write 发生的延迟 如果此服务器配置为同步,则提交时 待机。

flush_lag interval 从本地刷新最近的 WAL 到接收到此备用服务器有通知之间经过的时间 写入并刷新它(但尚未应用它)。这可以用来 衡量 synchronous_commit 级别 remote_flush 发生的延迟 如果此服务器配置为同步,则提交时 待机。

replay_lag interval 从本地刷新最近的 WAL 到接收到该备用服务器有通知之间经过的时间 写入,刷新并应用它。这可以用来衡量延迟 提交时发生的 synchronous_commit 级别 remote_apply 如果此服务器配置为同步备用服务器。

(格式化我的)

唉,新列似乎只适合同步复制(否则 master 不会知道确切的延迟),因此异步复制延迟问题似乎仍然存在 now()-pg_last_xact_replay_timestamp()...

【讨论】:

帖子主题未指定同步类型,因此我想以上信息可能有助于 smbd 在这里找到它【参考方案6】:

对于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;

如果您在 master 上运行此查询,结果将是:

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

如果你在同步的 slave 上运行这个查询,结果会是这样的:

 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 不同)并且它仅在@ 时有用987654331@ 列是false,因为lag 表示自上次提交操作以来经过了多少秒。在低流量站点中,此值是无用的。但是在高流量站点中,synced 可能(并且将会)几乎是时间 false,但是如果它的 lag 值足够小,则可以认为服务器已同步。

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

IF is_slavef(意思是不是slave,可能是master,所以是同步的); IF syncedt(意思是同步的slave,所以是同步的); IF(假设适用)lag <= :threshold:(意思是不是同步的slave,但离master不是太远,所以对我来说已经足够同步了)。

如果您想以秒为单位(包括小数),请执行以下操作:

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;

【讨论】:

【参考方案7】:

主人,你可以做select * from pg_stat_replication; 这会给你:

|  sent_lsn   |  write_lsn  |  flush_lsn  | replay_lsn  

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

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

那些可以告诉你你的偏移量在哪里。 从这个例子可以看出,replay on the replica 落后了。

【讨论】:

在 PostgreSQL 9.3 的 pg_stat_replication 中没有这样的列,这是这个问题明确询问的内容。【参考方案8】:

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

Replication-Lag-Visualizer

随时提出任何问题或贡献。

【讨论】:

以上是关于如何检查 PostgreSQL 中的复制延迟?的主要内容,如果未能解决你的问题,请参考以下文章

从 PostgreSQL 中的字段中提取数字

AWS RDS PostgreSQL:PostgreSQL 复制延迟的承诺价值是多少?

postgresql recovery.conf改变需要重启吗

开源数据库 PolarDB 为什么能捕获娃哈哈的心?

如何复制 PostgreSQL 数据库中的数据量?

如何检查 PostgreSQL 事务中的待处理操作