通过零停机模式升级大版本

本文介绍如何通过零停机的模式升级RDS PostgreSQL数据库大版本。

前提条件

背景信息

在零停机模式下,系统采用pg_upgrade将原实例升级至目标版本,并通过原生逻辑复制实现增量更新。升级过程中支持主动切换,并可在切换前对高版本实例进行验证;在升级开始至主动切换前,实例可保持正常的读写操作;在切换过程中,实例的只读时间为秒级。

RDS PostgreSQL控制台还支持通过蓝绿部署模式本地升级模式升级数据库大版本,不同模式的对比请参见大版本升级方案简介

升级费用

免费

注意事项

  • 业务影响:几乎无业务影响,原实例停机时间为秒级,停机时长取决于实例中的Sequence数量以及大事务的写入情况。

  • 复制槽(Replication Slots)

  • 参数变化

    • 如果原实例使用了新版本不支持的参数,在新版本中该参数会被自动删除。

    • 如果原实例的参数取值不在新版本对应参数取值的合法区间,则在新版本中,该参数将被设定为该版本参数模板的默认值。

    • 升级过程中,系统会暂时将statement_timeout的值修改为0,并在升级完成后恢复为原值。

  • DTS任务:如果待升级的实例作为数据传输服务(DTS)的源实例或目标实例,则升级后需要重建DTS任务

  • 插件兼容性问题:进行大版本升级时,系统将自动更新至最新的内核小版本,可能会遇到插件兼容性问题

  • 实例备份:在升级前后,均会对实例进行全量备份,以便于后续的克隆恢复。

不同升级阶段对实例的影响

升级阶段

影响

开始大版本升级

禁止进行任何DDL操作。

创建复制槽和发布

  • 禁止进行任何DDL操作。

  • 出现WAL日志堆积。

订阅端启动并建立逻辑复制关系

  • 禁止进行任何DDL操作。

  • WAL日志开始被消费,不再堆积。

  • 逻辑复制将产生一定的资源负载(与数据库数量及流量密切相关)。

开始切换

  • 禁止进行任何DDL操作。

  • 逻辑复制将产生一定的资源负载(与数据库数量及流量密切相关)。

  • 实例只读(只读时间与Sequence数量相关)。

完成切换(升级完成)

  • 逻辑复制槽被删除,逻辑复制所产生的资源负载被消除。

  • 实例恢复正常读写。

升级任务开始后,在升级历史页签,单击目标升级任务升级日志列的查看信息,即可查看详细的升级过程。

步骤一:升级前检查

  1. 访问RDS实例列表,在上方选择地域,然后单击目标实例ID。

  2. 在左侧导航栏单击大版本升级

    说明

    如果左侧导航栏中没有大版本升级,请检查RDS PostgreSQL实例版本及配置,具体请参见前提条件

  3. 升级检查页签中,单击创建升级检查报告

  4. 择选升级版本,且升级模式选择零停机后,单击确定

    此时,实例状态变为维护实例中,待升级检查完成后,实例状态会变为运行中

    当升级检查报告结果为成功警告时,可以进行后续的大版本升级步骤;若结果为失败,则需单击查看信息,根据报告内容修复异常检查项后,再次进行升级前检查。常见的报错及原因请参见解读RDS PostgreSQL大版本升级检查报告

    重要
    • 为确保升级顺利完成,当升级检查报告的检查结果为警告时,建议根据报告内容修复异常检查项后,再次进行升级前检查,直至检查结果为成功

    • 升级检查成功后,如果在主实例中创建了插件,需重新执行检查。

步骤二:升级大版本

  1. 单击升级实例页签,阅读警告内容,然后选择升级版本,并单击创建升级任务

  2. 在弹出的窗口中,阅读提示内容,然后单击确定

  3. 创建大版本升级任务区域,选择升级模式零停机

  4. 单击立即创建

    当实例状态变为迁移中时,表示升级任务已正式启动。

    升级所需时间与实例中的数据库对象数量密切相关,数据库对象数量越多,升级所需时间越长。在进行大版本升级时,您可以在任务中心查看升级进度。

    重要
    • 升级任务创建后不支持修改或删除

    • 原实例状态为迁移中时,该实例不支持修改参数、重启、释放等运维操作。

步骤三:切换到高版本

  1. 验证高版本实例。

    当实例状态将从迁移中转变为迁出数据中时,表示逻辑复制已搭建完成,创建升级任务的过程将结束,您可以验证高版本实例的数据。

    进入升级历史页签,使用目标升级记录的高版本验证地址连接至高版本实例,以验证升级后的数据。

    说明

    高版本实例为只读模式,无法进行写入操作。

    image

  2. 切换到高版本实例。

    确定高版本实例的数据符合预期后,且升级结果同步中时,单击升级日志列的切换,将业务切换到高版本实例。

    image

    说明
    • 如果升级结果为其他状态,请参见升级结果说明进行处理。

    • 如果您决定放弃本次升级,可以单击升级日志列的取消。这将删除逻辑复制槽,取消逻辑复制对源实例的影响,并允许其执行DDL操作。

  3. 切换弹窗中设置容忍停写时间(单位:秒),并单击确定

    升级结果变为只读时,表示正在进行切换,此时实例状态为迁移中时。在大版本升级升级历史页签,单击升级日志列的中断按钮,取消此次切换操作。

    说明

    可以通过在切换时设置容忍停写时间,主动等待复制延迟消除,保障数据一致性。在此过程中,升级结果将变为只读。如果超出此时间,则系统将返回到同步中状态,并解除只读限制。

  4. 查看切换结果。

    升级结果变为成功时,表示切换成功,当实例状态为运行中时。

    在实例基本信息页,可以查看实例当前的版本信息。

    说明

    升级完成后,在升级历史页签,单击目标升级任务升级日志列的查看信息,即可查看升级过程中实例的只读时间及详细的升级过程。其中只读时间为切换时间切换完成时间之间的时段,此时间段不包括因DNS缓存未刷新而导致无法连接的时间。

升级结果说明

升级过程中,升级历史页签的升级记录中,包含以下升级结果

升级结果

实例状态

含义

可执行动作

运行中

迁移中

升级任务正在运行。

无。

同步中

迁出数据中

逻辑复制状态正常。

  • 切换:切换到高版本实例。

  • 取消:放弃本次升级。

复制断开

迁出数据中

逻辑复制状态异常。

  • 查看升级日志确定复制异常原因。

  • 取消:放弃本次升级。

只读

迁移中

正在切换,实例为只读模式,并且正在同步Sequence。

中断:取消此次切换操作。

切换

迁移中

Sequence同步已完成,现正进行收尾工作。

无。

取消

运行中

升级任务取消。

无。

成功

运行中

升级任务成功。

无。

相关API

API

描述

UpgradeDBInstanceMajorVersionPrecheck

RDS PostgreSQL实例大版本升级检查。

DescribeUpgradeMajorVersionPrecheckTask

查询RDS PostgreSQL实例大版本升级检查报告。

UpgradeDBInstanceMajorVersion

RDS PostgreSQL实例升级数据库大版本。

DescribeUpgradeMajorVersionTask

查询RDS PostgreSQL实例大版本升级历史任务。

相关文档

常见问题

大版本升级期间,是否能变更实例?比如变更实例规格?

大版本升级期间不支持变更实例,必须在大版本升级完成后才能进行其他操作。

大版本是否支持自动升级?

暂不支持自动升级数据库大版本。

是否支持大版本降级?

升级后暂不支持进行大版本降级操作,如需降级,请购买低版本实例后,使用DTS迁移,将实例迁移至低版本中。

升级数据库大版本后,在新实例中创建raster_overviews视图时,提示raster_overviews冲突,如何处理?

如果PostGIS版本小于2.5.2RDS PostgreSQL版本为1011,升级插件后,再升级数据库大版本到PostgreSQL12,在新实例中创建raster_overviews视图可能会出现raster_overviews冲突的问题。

解决方法如下:

  1. 在原实例中升级PostGIS插件版本。

    如下命令需执行两遍,以确保成功。

    SELECT PostGIS_Extensions_Upgrade();
    SELECT PostGIS_Extensions_Upgrade();
  2. 根据业务判断是否使用了PostGIS Raster插件,选择对应的升级方法。

    使用了PostGIS Raster插件
    1. 在原实例中执行如下命令,修改raster_overviews视图。

      ALTER EXTENSION PostGIS_Raster DROP VIEW raster_overviews;
      CREATE OR REPLACE VIEW raster_overviews AS SELECT 1;
    2. PostgreSQL实例进行大版本升级,至少升级到PostgreSQL 12或以上版本。

    3. 升级完成后,在新实例中重新创建视图。

      CREATE 
      OR REPLACE VIEW raster_overviews AS 
      SELECT 
        current_database() AS o_table_catalog, 
        n.nspname AS o_table_schema, 
        c.relname AS o_table_name, 
        a.attname AS o_raster_column, 
        current_database() AS r_table_catalog, 
        split_part(
          split_part(s.consrc, '''::name', 1), 
          '''', 
          2
        ): :name AS r_table_schema, 
        split_part(
          split_part(s.consrc, '''::name', 2), 
          '''', 
          2
        ): :name AS r_table_name, 
        split_part(
          split_part(s.consrc, '''::name', 3), 
          '''', 
          2
        ): :name AS r_raster_column, 
        trim(
          both 
          from 
            split_part(s.consrc, ',', 2)
        ): :integer AS overview_factor 
      FROM 
        pg_class c, 
        pg_attribute a, 
        pg_type t, 
        pg_namespace n, 
        (
          SELECT 
            connamespace, 
            conrelid, 
            conkey, 
            pg_get_constraintdef(oid) As consrc 
          FROM 
            pg_constraint
        ) AS s 
      WHERE 
        t.typname = 'raster' : :name 
        AND a.attisdropped = false 
        AND a.atttypid = t.oid 
        AND a.attrelid = c.oid 
        AND c.relnamespace = n.oid 
        AND c.relkind = ANY(
          ARRAY[ 'r' : :char, 'v' : :char, 'm' : :char, 
          'f' : :char ]
        ) 
        AND s.connamespace = n.oid 
        AND s.conrelid = c.oid 
        AND s.consrc LIKE '%_overview_constraint(%' 
        AND NOT pg_is_other_temp_schema(c.relnamespace) 
        AND has_table_privilege(c.oid, 'SELECT' : :text); ALTER EXTENSION PostGIS_Raster 
      ADD 
        VIEW raster_overviews;
    未使用PostGIS Raster插件
    1. 在原实例中执行如下命令删除插件。

      DROP EXTENSION PostGIS_Raster;
    2. PostgreSQL实例进行大版本升级,至少升级到PostgreSQL 12或以上版本。

如何避免在升级过程中出现复制槽抢占导致的数据不同步问题

  • 如果您需要将订阅数据保留在源端(低版本实例),那么在升级的过程中,确保源端不会因负载过大而导致宕机。否则,可能导致复制槽被目标端(高版本实例)抢占,从而出现数据不一致的情况。

    升级完成后,请使用以下SQL语句在目标端的数据库关闭订阅。

    \c your_database
    ALTER SUBSCRIPTION your_subscription_name DISABLE;
  • 如果您需要将订阅数据保存在目标端,请在升级前关闭源端的订阅,再进行大版本升级,升级完成后,请打开目标端的订阅。SQL示例如下:

    • 在源端关闭订阅。

      \c your_database
      ALTER SUBSCRIPTION your_subscription_name DISABLE;
    • 在目标端开启订阅。

      \c your_database
      ALTER SUBSCRIPTION your_subscription_name ENABLE;
说明

如何处理升级后订阅数据不一致的问题?

  1. 升级成功后,清空目标端(高版本实例)表数据,重新创建订阅并设置copy_data=true。详情请参见ALTER SUBSCRIPTION

  2. 使用CONFLICT关键字将源端(低版本实例)消费的数据导入到目标端,示例如下。

    CREATE TABLE my_tbl(id INT PRIMARY KEY, t TIMESTAMP, val TEXT);
    
    INSERT INTO my_tbl VALUES (1, CURRENT_TIMESTAMP, 'a');
    INSERT INTO my_tbl VALUES (2, CURRENT_TIMESTAMP, 'b');
    INSERT INTO my_tbl VALUES (3, CURRENT_TIMESTAMP, 'c');
    
    -- in case with newer timestamp: do update
    INSERT INTO my_tbl VALUES (1, CURRENT_TIMESTAMP, 'd') ON CONFLICT(id) DO UPDATE
    	SET t = excluded.t,
    		val = excluded.val
    	WHERE my_tbl.t < excluded.t;
    
    -- in case with older timestamp: do nothing
    INSERT INTO my_tbl VALUES (2, CURRENT_TIMESTAMP - '10 hours'::interval, 'e') ON CONFLICT(id) DO UPDATE
    	SET t = excluded.t,
    		val = excluded.val
    	WHERE my_tbl.t < excluded.t;
    
    -- in case with new val: just insert
    INSERT INTO my_tbl VALUES (5, CURRENT_TIMESTAMP - '10 hours'::interval, 'f') ON CONFLICT(id) DO UPDATE
    	SET t = excluded.t,
    		val = excluded.val
    	WHERE my_tbl.t < excluded.t;