复制是数据库高可用性 (HA) 的核心。虽然可以通过各种方法复制磁盘上的数据,无论是硬件还是软件、磁盘、文件或基于块的解决方案,但如果没有数据库的在线副本,就无法实现 HA 设置。
本博客更详细地探讨了影响 PostgreSQL 复制的挑战/冲突,但在此之前,让我们了解一些关键概念以及 PostgreSQL 中复制的演变。
PostgreSQL 中复制的演变
毫不奇怪,PostgreSQL 社区多年来一直投资于构建可靠的复制功能,以帮助提供 HA 和 DR。以下是复制核心多年来如何演变的时间表,从预写日志 (WAL) 开始,最后讨论同步流复制。
预写式日志记录 (WAL)
作为 7.1 版本的一部分,预写式日志记录 (WAL) 于 2001 年添加到 PostgreSQL。这是确保耐久性的重要一步,因为它确保了 ACID 合规性的“D”。除了持久性之外,这还通过减少多次写入同一页面的需求,从而来提高事务的性能和响应时间。
复制功能
在引入 WAL 几年后,第一个主要的复制功能,即热备份,在 PostgreSQL 中实现。
温备份或温备份日志传送
2006 年的 8.2 版本中引入了热备份功能。该功能引入了持续归档和持续恢复的概念。
在待机状态下,服务器将不断恢复。这意味着虽然服务器在线,但它不能接受任何连接。它所做的只是处理它从主服务器的持续归档过程中接收到的 WAL 文件段。
这是异步复制。多条 WAL 记录被打包到一个文件中并运出备用数据库。在主服务器崩溃的情况下可能会丢失数据,一些 WAL 记录可能尚未发送。
所以这是 PostgreSQL 迈向 HA 解决方案的第一步!
从温到热:流式复制
在 2010 年的 9.0 版本中,引入了流式复制和热备份。添加了两个新的 postmaster 进程;walsender 和 walreceiver。这本质上与持续归档和持续恢复的概念相同,但通过后台进程实现。但是,这使备用数据库现在能够接受传入连接并运行只读查询。
这些后台进程还负责将 WAL 文件刷新到主服务器和备用服务器上的磁盘。
作为此版本的一部分,添加了两个用于监视复制的功能;pg_last_xlog_receive_location 和 pg_last_xlog_replay_location。
但是,复制仍然是异步的,并且在主服务器崩溃的情况下可能会丢失数据。
同步流复制
2011 年的 9.1 版本通过同步流复制消除了潜在的数据丢失问题。这确保了适用于 HA 系统的严格数据完整性保证。通过发出“SET LOCAL synchronous_replication TO OFF”,可以使事务块的同步机制异步。
此外,此版本还引入了仲裁、优先级、连接和活动备用的概念。
设置流复制
设置流复制实际上相当简单。这是一个简单的五步过程:
- 创建用于复制的用户。我们将在此示例中使用 rep_user。
-- Let’s create rep_user with a replication role in the primary database.
CREATE USER rep_user REPLICATION;
- 将复制用户添加到主服务器上的 pg_hba.conf。
# TYPE DATABASE USER ADDRESS METHOD
host replication rep_user <ip address range> <auth_method>
- 通过“pg_ctl reload”、SQL 函数 pg_reload_conf() 或通过“kill -HUP”在主服务器上重新加载 pg_hba.conf。
- 使用带有“-R”选项的 pg_basebackup 对主数据库进行备份,以将复制信息写入新数据目录。
- 启动备用服务器。
至此流复制已启用。PostgreSQL 官方文档在这里更详细地解释了流复制配置。
复制视图和配置
在配置复制方面,该过程变得有点棘手,因为必须以最佳方式配置主服务器、发送服务器和备用服务器以满足性能和正常运行时间的要求。
发送服务器是复制设置中的任何 PostgreSQL 服务器,它将 WAL 段传送到备用服务器。这可能是级联复制配置中的主服务器或中间备用服务器。
配置
主服务器、发送服务器和备用服务器大约有 20 种不同的配置选项。这些配置用于 WAL、vacuum、连接、提升、复制延迟和复制反馈。
视图
pg_stat_replication 和 pg_stat_wal_receiver 视图分别提供有关主服务器和备用服务器上的复制的信息。
在主服务器上,pg_stat_replication 包含每个连接到备用服务器的 walsender 进程一行。每个给定备用服务器还显示应用程序和客户端连接信息以及复制、写入、刷新、重放 LSN 和间隔的状态。对于主服务器,它显示已发送的 LSN。
在备用服务器上,pg_stat_replication 为连接和 LSN 公开与 pg_stat_replication 非常相似的信息,但如果有的话,还会显示复制槽。它只有一行用于 walreceiver 进程。
复制冲突
复制冲突仅发生在备用服务器上。主服务器上没有冲突。当 walreceiver 进程启动 WAL 重做操作时,冲突发生在待机状态。WAL 重做操作需要独占锁,它可能由任何长时间运行的查询或事务持有。重做操作一直等到超时,之后任何持有阻止 WAL 处理的锁的后端都将终止。这些终止被归类为复制冲突。这些冲突的性质可能非常不同。
PostgreSQL 有 pg_stat_database_conflicts 视图,它告诉我们什么类型的冲突以及发生了多少。
我们可以方便地忽略pg_stat_database视图,因为它只有一个 BigInt 字段来维护冲突计数。它并没有真正提供对这些冲突性质的任何见解。
pg_stat_database_conflicts
在备用服务器上,pg_stat_database_conflicts 每个数据库有一行显示由于恢复而导致的数据库范围的查询取消统计信息。这是一个相当简单的视图,包含 datid、datname 和五个用于计算不同类型冲突的方面:
- 表空间,
- 锁,
- 快照,
- 缓冲针
- 死锁
表空间冲突
如果删除了预期的 temp_tablespaces,则可能会发生表空间冲突。temp_tablespaces 用于临时表、索引和排序操作。
这些类型的冲突有些不常见,因为这些操作之间的距离非常少。
锁冲突
当您在备用数据库上查询表的内容并且在主数据库上远程更改该表时,可能会发生锁定冲突。
这将导致锁定争用,因为 walreceiver 进程希望通过获取索引/关系上的 ACCESS EXCLUSIVE 锁来进行更改。但是,另一个查询持有 ACCESS SHARE 锁。
快照冲突
Snapshop 冲突是在后端进程尝试访问备用服务器上已在主服务器上清空的行时产生的。
缓冲针冲突
这些主要是由热链修剪或版本 14 中 btree 索引的版本重复流失引起的,因为它需要在页面上进行排他锁。
这些类型的冲突并不常见。
死锁冲突
这些是由于待机死锁而发生的查询取消引起的冲突。
其他冲突
可能还有其他类型的冲突,但 pg_stat_database_conflicts 视图没有捕获这些冲突。例如,一个人可能会遇到数据库冲突,其中一个数据库在主数据库上被删除,但备用数据库可能有使用它的活动连接。
调查:PostgreSQL 复制面临的问题
根据在朋友和同事中进行的一项调查,我发现超过 50% 的受访者遇到过 PostgreSQL 复制问题。
遇到的问题和冲突的类型也让我们深入了解在配置复制时应该关注什么。
如果您希望与我分享您在 PostgreSQL 复制方面的经验,那么您可以使用此 Google 表单。
结论
我会写更多的博客,因为我将讨论这些复制冲突是如何发生的,以及备用服务器如何在内部做出反应。真正的关键是获得更好的底层视角,以便我们可以改进复制配置以避免此类冲突,从而提高性能、更好的正常运行时间和更简单的调试。
原文标题:PostgreSQL Replication and Conflicts
原文作者:Hamid Akthar
原文地址:https://www.percona.com/blog/postgresql-replication-and-conflicts/




