架构
你可能不了解 Coffee Meets Bagel,我们是一个精心策划的约会应用。每天中午,约会者都会收到一定数量的高质量候选人。我们的负载模式具有非常好的可预见性。在撰写这篇文章的前一周,我们的平均交易数徘徊在每秒 3 万笔左右,而在更大的市场中,我们的最高交易数是每秒 6.5 万笔。
在升级之前,我们在 AWS i3.8xlarge 实例上运行了 6 个 Postgres 服务器。其中包扩一个主节点,三个服务于只读 Web 流量的副本(通过 HAProxy 实现负载均衡),一个专用于异步工作线程的服务器,还有一个用于 ETL 和 BI 的服务器。
我们使用 Postgres 内置的流复制来保证副本集群是最新的。
升级原因
在过去的几年里,在很大程度上,我们忽略了数据层,因此它们已经有点老迈了。特别是我们的主服务器已经积攒了很多问题——它在线已经有大约 3 年半的时间了,各种系统库和服务都打过补丁。
我提供给r/uptimeporn的数据
因此,它有许多让我们紧张的稀奇古怪的问题:新服务拒绝在 systemd 中运行(我们最后在一个 screen 会话中运行了一个>
此外,我们的磁盘使用开始变得不稳定。正如我前面提到的,我们在 EC2 i3.8xlarge 实例上运行 Postgres,该实例带有 7.6TB 的 NVMe 存储。和 EBS 不同,它不能动态调整大小,所以有多大就是多大,而且磁盘的 75%已经填满。为了支持未来的增长,我们必须升级实例大小。
我们的需求
我们知道三种 Postgres 升级方法:典型的备份和还原过程、pg_upgrade 和逻辑复制。
我们很快就放弃了备份和还原方法,因为我们的数据集有 5.7TB,需要花费的时间太长了。pg_upgrade 虽然快,但它是就地升级,不满足条件 2 和 3。所以,我们下一步是进行逻辑复制。
过程
关于 pglogology 的安装和使用,已经有很多资料,所以我就不重复了,下面这些链接我认为非常有帮助:
我们创建了一个 Postgres 12 服务器,它将成为我们新的主服务器,并使用 pglogical 来同步所有数据。一旦它复制完旧数据并开始复制传入的更改,我们就在它后面添加流副本。当我们每准备好一个新的流副本,就把它添加到 HAProxy 中,同时删除一个旧的 9.6 副本。我们就这样一直做,直到除了主服务器之外的所有 Postgres 9.6 服务器都已退出,此时,我们的状态如下:
在这种状态下,我们就会安排一个维护窗口来执行故障切换。同样,关于这个过程,网上有很好的文档,所以这里我只粗略地描述一下我们所做的事情:
总之,对于我们来说,这个过程很顺利。虽然这是一次规模比较大的基础设施迁移,但我们没有遇到任何意外的停机或者错误。
经验教训
虽然这个项目取得了很大的成功,但我们也遇到了一些问题。最可怕的是差点搞挂我们的 Postgres 9.6 Primary…
教训 #1:同步缓慢会很危险
首先是一些关于 pglogical 的背景信息:pglogical 的工作方式是,提供方数据库(在本例中是我们的旧 9.6 Primary)上的发送方进程将解码预写日志,提取逻辑更改,并将它们发送到订阅方数据库。
如果订阅方速度慢了,那么提供方的 WAL 段就会开始累积,这样,当订阅方赶上时就不会丢失任何数据。
当你向副本流添加表时,pglogical 首先需要同步表数据。这是使用 Postgres 的 命令完成的。然后,在提供方数据库上 WAL 段将开始累积,这样,在 开始后提交的更改可以在初始同步完成后传输到订阅方,确保数据不会丢失。
也就是说,在实践中,如果你正在一个写入/更新频繁的系统中同步一个较大的表,那么你需要密切关注磁盘使用情况。我们第一次尝试同步最大的表(4TB)时,初始 语句运行了一天多,在此期间,我们在提供方节点上累积了大约 1TB 的 WAL。
你可能还记得,我们在前面提到过,我们的旧数据库服务器只剩下大约 2TB 的空闲磁盘空间。从用户数据库的磁盘使用情况来看,只有约四分之一的表复制了,我们认定,我们将无法在磁盘空间耗尽之前完成,因此我们迅速取消了同步过程。
在初始同步期间,旧主数据库上的可用磁盘空间
然后,我们对订阅方数据库做了以下更改,以加快同步:
这四个更改显著提高了订阅方数据库摄取数据的速度,我们在第二次尝试时用不到 8 小时就完成了表的同步。
教训 #2: 每个更新都被记录为冲突
当 pglologic 断定发生了冲突时,它会发出一条日志消息,比如“
然而,我们观察到,订阅方处理的每个更新都会被记录为冲突。仅经过几个小时的复制,订阅方数据库就已经写入了 1GB 的冲突日志。
参与 Hacker News 讨论,请点击这里。
查看英文原文 :Our Journey to PostgreSQL 12