当前位置: 首页 > 科技观察

一次近乎完美的PostgreSQL版本大升级实践_0

时间:2023-03-12 08:08:54 科技观察

如何实现近乎完美的数据库版本大升级?本文详细介绍了GitLab将PostgreSQL从9.6版本升级到11版本的努力。2020年5月,我们与OnGres合作对GitLab上的Postgres集群进行了一次大版本更新,从9.6版本升级到11版本。所有升级都在维护中运行窗口没有任何错误;更新中涉及的所有内容、规划、测试、全流程自动化全部解包,实现近乎完美的PostgreSQL升级。在本次版本更新中,我们面临的最大挑战是如何利用一个精心策划的pg_upgrade,方便高效的对整个项目进行重要的版本升级。为此,我们需要制定回滚计划,确保12节点集群6TB数据的一致性,同时优化恢复目标时间(RTO)后的容量,为600万用户提供每秒30万笔聚合交易。应对工程挑战的最佳解决方案是遵循蓝图和设计文档。在创建蓝图的过程中,我们需要定义目标问题,评估最合适的解决方案,并考虑每个解决方案的优缺点。在这里,我们附上为该项目准备的蓝图的链接。https://gitlab.com/gitlab-com/gl-infra/readiness/-/tree/master/library/database/postgres/Postgresql-upgrade/blueprint/1。为什么要升级PostgreSQL我们决定在GitLab13.0中停止对PostgreSQL10.0的支持,而PostgreSQL9.6版本将在2021年11月EOL(项目结束),因此我们需要采取相应行动。以下是PostgreSQL9.6和11版本的主要区别:表分区支持LIST、RANGE和HASH存储过程支持事务即时编译(JIT),加快查询表达式的执行速度并行查询,增加并行数据定义新版本功能PostgreSQL继承了版本10中的“逻辑复制—发布/订阅数据分发框架”,该功能可以让以后的升级更加顺畅,并简化其他相关流程。基于Quorum的提交(commit)确保事务可以在集群中的指定节点上提交。改进了分区表查询的性能2.环境和架构PostgreSQL集群的基础设施容量由12个n1-highmem-96GCP实例组成,服务于OLTP以及异步管道。同时,它还有两个不同规格的BI节点,每个节点有96个CPU核心和614GB内存。HA集群通过Patroni进行管理和配置,以确保Consul集群及其在异步流复制中的所有副本的领导者选举一致,使用复制槽和WAL复制GCS桶。https://github.com/zalando/patroni我们的配置目前使用PatroniHA解决方案,它会持续收集有关集群、领导者检测和节点可用性的关键信息。该解决方案是使用Consul的DNS服务等关键功能实现的,该服务反过来会更新PgBouncer端点,以确保读写和只读流量使用不同的模式。由于HA原因,GitLab.com架构有两个副本不在只读服务器列表池中,但由服务于API的ConsulDNS支持。在对GitLab架构进行了几次改进之后,我们能够将项目整体减少到7个节点。另外,我们整个集群平均每周每秒约181,000个事务,如下图所示,周一的流量会明显增加,并从周一到周五/周六保持这个吞吐量。我们需要让维护影响尽可能少的用户,所以流量数据的统计对于设置合适的维护窗口非常重要。GitLab.com上整体的连接统计项目数量在一天中最繁忙的时候可以达到每秒25,000个事务。GitLab.com上的commit数量统计同时,项目处理的交易峰值可以达到每秒30万笔交易,GitLab.com可以达到每秒6万个连接。3.我们的升级要求在升级生产环境之前,我们首先确定了一些要求:PostgreSQL11不能有回归。我们开发了一个自定义基准来运行更广泛的回归测试集,目的是识别PostgreSQL11中潜在的查询性能下降。升级应该在项目范围内进行,并在维护窗口内完成。使用pg_upgrade升级,它依赖于物理而非逻辑或复制。保留9.6集群的样本。并不是所有的节点都需要升级,我们应该保留一些9.6的节点用于回滚。升级应该完全自动化,以减少人为错误的可能性。所有数据库升级的维护窗口只有30分钟。升级应该被记录和发布。4.项目为了使生产升级顺利进行,我们将项目分为以下四个阶段:第一阶段:在封闭环境中开发自动化在staging备份的PostgreSQL环境中开发ansible-playbook并进行测试。https://gitlab.com/gitlab-com/gl-infra/db-migration/-/tree/master/pg-upgrade独立环境的使用让我们可以随时停止、启动或恢复备份,并且也让我们可以专注于开发,环境可以随时回滚到升级前。我们使用暂存备份来进行环境中的项目升级。在这个过程中,我们也遇到了一些挑战,比如在迁移数据库的过程中如何监控不同的程序。Phase2:升级开发和配置管理阶段性集成在staging中在Chef中集成配置管理,运行数据库磁盘快照(可用于恢复更新前的状态)。告知用户,此维护窗口将努力将对他们工作的影响降至最低,并允许在没有数据丢失风险的情况下进行安全升级。在迭代配置管理和集成测试之后,我们开始在登台上运行端到端测试。这些测试是在内部公开的,所以共享这个环境的其他团队会知道在这段时间内暂存暂时不可用。第三阶段:在staging上测试端到端升级正式运行前检查环境。我们有时会在这一步发现认证问题,有时会做一些小的调整来提高测试效率。停止GitLab上的所有应用程序和流量,在CloudFlare和HA-proxy上添加维护模式,停止所有可以访问数据库的应用程序,包括数据库、sidekiq、workhorse、WEB-API等。升级集群中六个节点中的三个。类似于生产中一些场景的策略,我们也准备了回滚计划。为PostgreSQL更新运行ansible-playbook。首先是数据库领导节点,然后是一些辅助节点。升级后:我们在ansible-playbook中运行一些自动化测试来检查复制的数据是否与原始数据匹配。接下来,启动应用程序,以便我们的QA团队可以运行一些测试。他们在升级后的数据库上运行了本地单元测试,我们调查了负面结果。测试结束后,我们再次停止程序,将staging集群恢复到9.6版本,关闭升级节点到11版本,最后启动老版本集群。Patroni会推广其中一个节点,应用启动后集群可以收到流量反馈。我们将Chef配置恢复到9.6版本的集群,并重建数据库,留出6个节点用于下一次测试。我们在暂存阶段总共进行了7次测试,并根据反馈继续完善程序。Phase4:UpgradingintoProduction生产环境中的步骤与staging中的步骤类似,我们计划迁移8个节点并留下4个作为备份。执行项目前检查宣布维护开始运行ansible-playbook以停止流量和应用程序运行ansible-playbook以进行PostgreSQL升级开始验证测试并恢复流量。我们只运行了所需的测试,以便可以在较短的维护窗口内完成所有操作仅当数据库不一致或QA测试出错时才调用回滚计划在9.6版中使用四个节点初始化集群。有了这四个节点,我们可以在低流量期间恢复GitLab上的活动。开始接收流量,这样您就可以最大限度地减少停机时间。在维护和升级前使用磁盘快照恢复其他节点升级中的所有步骤在用于运行项目的模板中有详细说明以备不时之需,将PostgreSQL数据文件升级到未来的主要版本。https://www.postgresql.org/docs/11/pgupgrade.html正如官方PostgreSQL文档中所写,pg_upgrade工具通过避免执行转储/恢复来升级PostgreSQL版本。这里有几个细节需要注意:PostgreSQL的主要版本增加了新特性,这些特性经常改变系统表的布局,但内部数据存储格式基本保持不变。如果大版本升级改变了数据格式,pg_upgrade就不能继续使用了。因此,我们必须首先验证这些版本之间发生了什么变化。同样重要的是要注意任何外部模块必须是二进制兼容的,尽管你不能用pg_upgrade来检查这一点。对于GitLab的更新,我们在升级前卸载了postgres_exporter等视图和扩展,以便升级后重新创建。出于兼容性原因,我们需要稍微修改它们。https://github.com/wrouesnel/postgres_exporter在更新之前,您必须先安装新版本的二进制文件。新的PostgreSQL二进制文件和扩展安装在需要升级的主机上。pg_upgrade在使用时有很多选项。我们选择在Leader节点上使用pg_upgrade的链式模式,因为维护窗口很短,只有两个小时。这种模式可以通过inode硬链接文件,避免了复制6TB文件的麻烦。缺点是旧数据集群无法回滚到9.6版本。我们保留了9.6版的副本和GCP快照作为我们回退计划的回退路径。由于从头开始重建副本是不可能的,我们选择使用rsync的增量功能进行升级。pg_upgrade的官方文档也写道:“从主服务器上的旧数据库集群目录和新数据库集群目录上方的目录,在每个备用服务器的主服务器上运行此命令。”Ansible-playbook对于这一步的实现,是通过leader节点到每个replica的task,在新老数据目录下的父目录下触发rsync命令。6.回归测试基准任何迁移或数据库升级都需要在最终生产升级之前进行回归测试。对于团队来说,数据库测试是升级过程中至关重要的一步。根据生产过程中的查询次数进行性能测试,结果存储在pg_stat_statement表中。这些都在同一个数据集上运行,一次在9.6版,一次在11版迭代。这个循序渐进的过程可以在以下公共问题中找到:https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/准备工具创建测试环境计算能力使用JMeter工具来runbenchmarks最后,基于OnGres在这个benchmark上的工作,GitLab在未来会跟进新的benchmarks。主生产数据库集群容量评估数据库容量及饱和度分析7.升级过程:全自动化完成在升级项目中,升级团队坚持使用自动化和基础设施及代码工具(IaC)。所有流程都必须完全自动化,以减少维护窗口期间的人为错误。pg_upgrade的所有运行步骤都可以在这个GitLabpg_upgradetemplateissue中找到。https://gitlab.com/gitlab-com/gl-infra/db-migration/-/blob/master/.gitlab/issue_templates/pg_upgrade.mdGitLab.com的环境由Terraform和Chef共同管理,所有升级是自动化的它是用Ansible2.9剧本和角色编写的。我们使用两个ansible-playbook来完成升级自动化:一个ansible-playbook控制流量和应用程序:将Cloudflare设置为维护状态,不接受流量停止HA-proxy停止访问数据库中间件:Sidekiq,Workhorse,WEB-API另一个ansible-playbook运行升级过程:协调所有数据库和连接池的流量控制Patroni集群和Consul实例在主节点和辅助节点上执行升级收集升级后的统计信息使用Chef同步更改以维护配置管理的完整性验证集群完整性和状态执行GCP快照(可能)回滚流程playbook以交互方式逐一运行所有任务,允许程序员跳过任何给定的执行点或暂停程序。参与分阶段测试和迭代的所有团队成员都必须完成升级过程中的所有步骤。staging环境可以让我们通过练习提前发现升级过程中潜在的漏洞。在staging中执行和迭代自动化过程使我们能够实现从PostgreSQL9.6版到11版的基本无错误升级。为了完成此版本升级,GitLab的QA团队向我们反馈了测试中发现的一些问题,而这部分工作可以在本期中找到。https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/106#note_3321708378。PostgreSQL升级前步骤升级工作的第一步是“升级前”,涉及Rollexample。我们做了相应的分析,保证新集群不会丢失吞吐量。从8个示例开始,我们将4个9.6版本的示例与标准Patroni集群同步,为后续可能需要的回滚做准备(总共12个实例)。在这个阶段,我们还需要停止依赖PostgreSQL的服务,比如PgBouncer、Chef客户端、Patroni服务。必须在更新正式开始之前通知Patroni,以避免任何虚假的领导者选举,通过GCP快照(通过相应的低级备份API获得)进行一致的备份,并通过运行Chef应用新设置。https://www.cybertec-postgresql.com/en/exclusive-backup-deprecated-what-now/?gclid=CjwKCAjwltH3BRB6EiwAhj0IUBjiSxBdmS11SUpITLCmk-oPkBa7udOWyA6bK6hig8neaiJc8n1WexoCq8UQAvD_BwE9。首先,停止升级阶段的所有节点。然后,运行以下检查:pg_upgradeversioncheck验证所有节点是否已同步并且不再接受任何流量一旦主节点数据升级,将触发rsync进程以同步所有副本数据。升级完成后,启动Patroni服务,以便所有副本都可以轻松更新到新集群的配置。通过Chef安装二进制文件,新集群的版本设置在来自GitLab.com的同一个MR中定义,可以为数据库中的扩展安装。最后阶段包括恢复流量、运行初始真空期以及最后启动PgBouncer和Chef客户端服务。10.迁移日结束,我们都准备好运行在线升级,团队在世界标准时间周日早上8:45开始开会(有些人是晚上)。服务最多会下线两个小时,等到最后通知下达后,工程团队才终于可以上手。升级过程从停止所有流量和相关服务开始,这是为了防止用户在更新期间访问网站。下图为服务更新前、维护期间(图标空白部分)、维护结束恢复流量后的流量和HTTP统计。GitLab.com上的统计图,从维护到完成整个过程用了四个小时,其中只有两个小时的离线时间。另外,我们记录了PostgreSQL更新的全过程,发布在GitLabUnfiltered上。https://youtu.be/TKODwTtKWew