|
| 1 | +# How to determine the replication lag |
| 2 | + |
| 3 | +> 我每天都会发布一篇新的 PostgreSQL "howto" 文章。加入我的旅程吧 — 订阅、提供反馈、分享! |
| 4 | +
|
| 5 | +## 在主节点/备节点领导节点上 |
| 6 | + |
| 7 | +当连接到主节点 (或级联复制情况下的备节点的领导节点) 时,你可以使用 `pg_stat_replication`: |
| 8 | + |
| 9 | +```sql |
| 10 | +nik=# \d pg_stat_replication |
| 11 | + View "pg_catalog.pg_stat_replication" |
| 12 | + Column | Type | Collation | Nullable | Default |
| 13 | +------------------+--------------------------+-----------+----------+--------- |
| 14 | + pid | integer | | | |
| 15 | + usesysid | oid | | | |
| 16 | + usename | name | | | |
| 17 | + application_name | text | | | |
| 18 | + client_addr | inet | | | |
| 19 | + client_hostname | text | | | |
| 20 | + client_port | integer | | | |
| 21 | + backend_start | timestamp with time zone | | | |
| 22 | + backend_xmin | xid | | | |
| 23 | + state | text | | | |
| 24 | + sent_lsn | pg_lsn | | | |
| 25 | + write_lsn | pg_lsn | | | |
| 26 | + flush_lsn | pg_lsn | | | |
| 27 | + replay_lsn | pg_lsn | | | |
| 28 | + write_lag | interval | | | |
| 29 | + flush_lag | interval | | | |
| 30 | + replay_lag | interval | | | |
| 31 | + sync_priority | integer | | | |
| 32 | + sync_state | text | | | |
| 33 | + reply_time | timestamp with time zone | | | |
| 34 | +``` |
| 35 | + |
| 36 | +此视图包含物理复制 (仅限于使用流复制的情况,非 WAL 传输方式) 和逻辑复制的信息。延迟情况在此视图中可以通过字节 (lsn 相关列) 或时间间隔 (lag 相关列) 进行衡量,并且可以为每个复制流观察到多个步骤。 |
| 37 | + |
| 38 | +要分析此视图中的 LSN 值,我们需要将它们与所连接服务器上的当前 `LSN` 值进行比较: |
| 39 | + |
| 40 | +- 如果是主服务器 (`pg_is_in_recovery()` 返回 false ),则使用 `pg_current_wal_lsn()` |
| 41 | +- 否则 (备节点领导节点),使用 `pg_last_wal_replay_lsn()` |
| 42 | + |
| 43 | +可以使用 `pg_wal_lsn_diff()` 函数或 `-` 操作符进行 LSN 的差值计算。 |
| 44 | + |
| 45 | +文档:[Monitoring pg_stat_replication view](https://postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-REPLICATION-VIEW). |
| 46 | + |
| 47 | +以下是一些查询延迟的示例: |
| 48 | + |
| 49 | +- [Netdata](https://github.com/netdata/netdata/blob/9edcad92d83dba359f5eb6c06d0741b50030edcf/collectors/python.d.plugin/postgres/postgres.chart.py#L486) |
| 50 | +- [Postgres exporter for Prometheus](https://github.com/prometheus-community/postgres_exporter/blob/2a5692c0283fddf96e776cc73c2fc0d5caed1af6/cmd/postgres_exporter/queries.go#L46) |
| 51 | + |
| 52 | +## 在物理备节点上 |
| 53 | + |
| 54 | +当连接到物理备节点时,获取其延迟时间间隔: |
| 55 | + |
| 56 | +~~~sql |
| 57 | +select now() - pg_last_xact_replay_timestamp(); |
| 58 | +~~~ |
| 59 | + |
| 60 | +在某些情况下,`pg_last_xact_replay_timestamp()` 可能返回 `NULL`: |
| 61 | + |
| 62 | +- 如果备节点刚刚启动并且尚未重放任何事务; |
| 63 | +- 如果主节点上没有最近的事务。 |
| 64 | + |
| 65 | +`pg_last_xact_replay_timestamp()` 的这种行为可能会导致错误的结论,认为备节点存在延迟,且复制不健康 — 这在低负载的环境 (例如非生产环境) 中并不罕见。 |
| 66 | + |
| 67 | +文档:[pg_last_xact_replay_timestamp](https://postgresql.org/docs/current/functions-admin.html#id-1.5.8.33.6.3.2.2.4.1.1.1). |
| 68 | + |
| 69 | +------ |
| 70 | + |
| 71 | +## 逻辑复制 |
| 72 | + |
| 73 | +在主节点 (在逻辑复制上下文中通常称为"发布端") 上可以观察到复制延迟。除了前面讨论的 `pg_stat_replication`,还可以使用 `pg_replication_slots`: |
| 74 | + |
| 75 | +```sql |
| 76 | +select |
| 77 | + slot_name, |
| 78 | + pg_current_wal_lsn() - confirmed_flush_lsn as lag_bytes |
| 79 | +from pg_replication_slots; |
| 80 | +``` |
| 81 | + |
| 82 | +------ |
| 83 | + |
| 84 | +## 混合情况:逻辑和物理复制 |
| 85 | + |
| 86 | +在某些情况下,你可能需要同时处理逻辑复制和物理复制。例如,考虑以下情况: |
| 87 | + |
| 88 | +- 集群 A:一个由 3 个节点 (主节点 + 2 个物理备节点) 组成的常规集群。 |
| 89 | +- 集群 B:也是主节点 + 2 个物理备节点,且主节点通过逻辑复制连接到集群 A 的主节点。 |
| 90 | + |
| 91 | +这是一种典型的情况,通常在涉及逻辑复制的复杂更改 (例如大版本升级) 时会发生。在某些时候,你可能希望将部分只读流量从集群 A 的备节点重定向到集群 B 的备节点。 |
| 92 | + |
| 93 | +在这种情况下,如果我们需要了解每个节点的延迟情况,并且希望代码能很好地适用于所有节点,这可能会有些棘手。 |
| 94 | + |
| 95 | +以下是解决方法 (感谢来自 GitLab 的 [Dylan Griffith](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121621)),假设我们可以从我们正在分析的节点和集群 A 的主节点获取信息 (记住上面的所有评论): |
| 96 | + |
| 97 | +首先,获取主节点的 LSN: |
| 98 | + |
| 99 | +```sql |
| 100 | +select pg_current_wal_lsn() as primary_lsn; |
| 101 | +``` |
| 102 | + |
| 103 | +然后获取观察节点的 LSN 位置,并使用它来计算以字节为单位的延迟值: |
| 104 | + |
| 105 | +```sql |
| 106 | +with current_node as ( |
| 107 | + select case |
| 108 | + when exists (select from pg_replication_origin_status) then ( |
| 109 | + select remote_lsn |
| 110 | + from pg_replication_origin_status |
| 111 | + ) |
| 112 | + when pg_is_in_recovery() then pg_last_wal_replay_lsn() |
| 113 | + else pg_current_wal_lsn() |
| 114 | + end as lsn |
| 115 | +) |
| 116 | +select lsn – {{primary_lsn}} as lag_bytes |
| 117 | +from current_node; |
| 118 | +``` |
0 commit comments