亚马逊AWS官方博客

保驾护航:手工搭建 Amazon RDS mysql 5.7/8.0 跨账号的迁移或容灾

背景

Amazon Relational Database Service RDS 是一项托管关系数据库服务,为您提供七种熟悉的数据库引擎供您选择,包括 Amazon Aurora MySQL-Compatible Edition、Amazon Aurora PostgreSQL-Compatible Edition、MySQL、MariaDB、PostgreSQL、Oracle 和 Microsoft SQL Server。 这意味着您当前用于现有数据库的代码、应用程序和工具也可以用于 Amazon RDS。Amazon RDS 可处理日常的数据库任务,如预置、打补丁、备份、恢复、故障检测和维修。

Amazon RDS 让您能够轻松地使用复制功能来增强生产工作负载的可用性和可靠性。使用多可用区部署选项,您可以执行关键任务工作负载,并且能够利用高可用性和内置的自动失效转移功能,从您的主数据库转移到同步复制的辅助数据库。利用只读副本,您可以针对进行大量读取操作的数据库工作负载进行横向扩展,突破单个数据库部署的容量限制。

现代 IT 系统中,容灾一直是不可或缺的一部分,硬件故障、自然灾害、人为错误还是网络中断,这些意外事件都有可能导致系统故障,影响业务的连续性和可用性,容灾系统正是为了应对这些非常情况的,当生产系统碰到这些问题的时候,容灾系统可以承担起相关的功能,保证业务的连续性。容灾系统中的数据库容灾更是不可或缺的保障,它是我们对抗各种意外事件和灾难的最后一道防线。通过建立健全的数据库容灾策略,我们可以保障数据的完整性、可用性和持久性,确保业务连续运营,并保障客户数据的安全。当您的数据库已经运行在 Amazon RDS 之上,那么你很轻松的可以通过控制台,点击几个按钮就可以实现数据库的高可用构架或者容灾复制,也就是传统 IDC 概念里面的“两地三中心”,官方文档中有相关介绍,大家可以参考用户指南,这里就不多做介绍了:https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/Welcome.html

如果目前您的 mysql 数据库是通过 Amazon RDS 建立,想实现跨账号的复制,本文就来介绍一下,这种情况下,如何实现 Mysql 的复制,可以用于实际场景,比如容灾复制,或者数据库迁移。

具体步骤

环境说明

此次实验主要是模拟 Mysql 的复制场景,由于 Mysql 5.7 和 8.0 在设置上有些区别,所以此次会分别模拟使用 Mysql 5.7 和 8.0 的场景。网上使用自建 Mysql 搭建主从复制的文章非常多,这里就不多做介绍了,这里源库和目标库都采用 Amazon RDS mysql。

其中此次实验中的数据同步分为两个阶段:

  • 全量数据,此文中全量数据数据复制使用快照的方式实现,从源数据库复制全量数据到从库的方式有很多,使用快照的方式是比较好的一种,对源数据库压力比较小,效率也比较高。我们在源账号对源数据库建立一个快照,然后共享给目标账号,作为全量数据的基础。
  • 增量数据,增量数据复制有两种方式(两种方式都需要开启 binlog)
    • 基于 binlog 的 position 的方式,MySQL 的 binlog(二进制日志)是一种日志文件,用于记录对数据库进行的更改操作,例如插入、更新和删除等。binlog 是 MySQL 的事务日志,它是用于实现数据库的持久性和数据恢复的重要组件。在全量复制已经完成的基础上,只需要在从库上应用全量数据之后所有的 binlog 的事务,那么从库就可以实现同步所有增量,达到和主数据库一直的目的,我们只需要找到全量数据,也就是快照生成时刻,binlog 的具体 position,就可以实现上述的目的。
    • 基于 GTID 的复制,GTID(Global Transaction Identifier)是 MySQL 数据库复制中的一种标识符,用于全局唯一标识事务。GTID 是在 MySQL 复制环境中引入的一种改进特性,旨在简化复制拓扑和提供更可靠的数据一致性。GTID 是 MySQL 复制中的一种全局事务标识符,在从库发起增量同步的指令的时候,mysql 会自动去确认哪些事务在主库上已经应用而在从库上没有应用,然后同步。它简化了复制拓扑的配置和管理,提供了更可靠的数据一致性和故障转移机制。通过使用 GTID,可以更轻松地实现高可用性和可靠的数据库复制。

源数据库所在 VPC 和从库所在 VPC 做 VPC 对等连接

由于源数据库和从库所在的数据库分属不同的账号,所以我们需要建立 VPC 对等连接,这样所有通讯就可以通过私有网络进行,方法在官方文档有详细描述,大家可以参考这里:https://docs.aws.amazon.com/zh_cn/vpc/latest/peering/create-vpc-peering-connection.html

本次实验使用的是在不同账户和同一区域中使用 VPC 请求 VPC 对等连接,步骤如下:

  • 首先通过以下网址打开 Amazon VPC 控制台:https://console.aws.amazon.com/vpc/
  • 在导航窗格中,选择 Peering Connections(对等连接)
  • 选择 Create Peering Connection(创建对等连接)
  • 按如下所示配置信息,并在完成后选择创建对等连接
    • 名称:您可以选择为您的 VPC 对等连接命名。这样做可创建具有 Name 键以及指定值的标签。此标签仅您自己可见;对等 VPC 的拥有者可以为 VPC 对等连接创建其自己的标签
    • VPC ID(请求者):选择您账户中要用于创建 VPC 对等连接的 VPC
    • Account:选择 Another account
    • 账户 ID:输入接受方 VPC 所有者的 AWS 账户 ID
    • VPC ID(接受方):输入要用于创建 VPC 对等连接的 VPC 的 ID

注意:双方的 CIDR 不能重叠,如果是长期运行的容灾构架,请尽量保证源数据库和从库处于同一可用区中(如何保证请咨询亚马逊云科技官方客服)。

准备源数据库

首先我们需要启动一个源数据库,源数据库可看作生产数据库,这里使用 Amazon RDS 建立一个 mysql 数据库即可,整个建立过程官方文档都有详细的描述,大家可以参考这里:https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/UserGuide/CHAP_GettingStarted.CreatingConnecting.MySQL.html

所有步骤可以参考上面的文档,一步一步创建即可,但是需要注意的是,在此次实验中,加密使用的密钥的选择会影响后续的操作步骤。首先,我们不建议选择不加密,然后加密选项有两种,一种是选择 Key Management Service (KMS)托管的 RDS 默认密钥加密,如下图所示,就是“(default)aws/rds”这个密钥;另一种是选择“客户管理的密钥”,也就是在 KMS 中手工建立一个密钥,然后使用这个密钥,如下图所示,arn:aws:kms:开头的密钥就是建立的客户管理的密钥。

“(default)aws/rds”这个密钥是无法共享给其他账号访问的,所以直接共享被这个密钥加密的快照,目标账号是无法解密并且访问的,但是客户管理的密钥创建的时候可以共享给目标账号的 root 用户访问,然后再通过目标账号 root 用户共享给其他 IAM 用户访问(在密钥创建的过程中尝试按照格式添加目标账号的 IAM user 的信息,一样可以生效,节省了步骤),这样在后续的操作过程中,其他账号访问共享的快照的时候,就没有加密解密的问题了,如下图所示:

源数据库参数,建立源数据库的时候,以下几个数据库参数需要注意:

  • binlog,binlog 需要打开,并且设置保留时间,建议 24 小时
    • 自建 Mysql 中,binlog 保留日期的参数为 expire_logs_days(单位:天),binlog_expire_logs_seconds(单位:秒),其中,mysql 5.7 使用第一个参数,但是 mysql 8.0 中两个参数都存在,官方文档有详细的解释,如下所示:如果 binlog_expire_logs_seconds 或 expire_logs_days 在启动时都没有设置值,则默认值适用,默认为 30天。如果 binlog_expire_logs_seconds 或 expire_logs_days 变量之一在启动时设置了非零值,则该值将用作二进制日志过期时间。如果在启动时对这两个变量都设置了非零值,则 binlog_expire_logs_seconds 的值将被用作二进制日志过期期限,而 expire_logs_days 的值将被忽略并发出警告信息。
    • 在 Amazon RDS mysql 中,需要使用存储过程来设置和查看,设置 binlog 保存时间的存储过程语法为:call mysql.rds_set_configuration(‘binlog retention hours’,24);查看的语法为:call mysql.rds_show_configuration。
  • GTID 相关,如果使用基于 GTID 的复制,那么就需要在源库上进行相关参数的配置(修改参数组)
    • gtid-mode 参数,此参数有如下选项,可以看出,源库上必须设置为ON
      • OFF,表示新事务是匿名事务(即没有 GTID),而且必须是匿名事务才能被复制
      • OFF_PERMISSIVE,指定新事务为匿名事务,但所有事务都可以被复制
      • ON_PERMISSIVE,指定新事务为 GTID 事务,但可以复制所有事务
      • ON,表示新事务是 GTID 事务,且必须是 GTID 事务才能被复制
    • enforce_gtid_consistency,此参数有如下选项,可以看出,源库上必须设置为 ON
      • OFF 允许事务违反 GTID 一致性
      • ON 阻止事务违反 GTID 一致性
      • WARN 允许事务违反 GTID 一致性,但会在发生违反时发出警告

设置好参数之后,就可以启动数据库了。

数据库复制用户的建立,我们需要准备一个数据库用户来进行数据库的复制,具体命令如下:

CREATE USER 'repl_user'@'mydomain.com' IDENTIFIED BY 'password';
GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user'@'mydomain.com';

测试表的建立,测试表我们可以建立一个只有一个整型字段的表,每秒插入一条数据,然后根据这个字段判断是否复制成功,我们需要建立一个数据库,然后在里面建立一张表(数据库名/表名可自行更改):

create database snx;
use snx
create table drid(id int(10));

准备测试数据,我们写一个 Linux shell,比如叫 insert_data.sh,每秒插入一条数据即可,shell 内容如下:

#!/bin/bash

host="endpoint of database"
user="your database user"
password="your password"
database="snx"
table="drid"
field="id"

value=1
while true; do
 mysql -h $host -u $user -p$password -D $database -e "INSERT INTO $table ($field) VALUES ($value);"
 sleep 1
 ((value++))
done

然后我们执行命令即可:

nohup sh insert_data.sh &

源数据库建立快照

Amazon RDS 控制台即可进行快照的建立,一键式操作,但是在后续的步骤中,如果增量复制选择的是基于 binlog 的 position 的时候,需要注意如下事项(基于 GTID 的则只需要建立快照,不需要记录如下的 binlog position):

  • RDS mysql 5.7 通过快照恢复的时候,通过 mysql-error-running.log 可以查找到类似如下的日志信息,可以用于定位快照建立时刻的数据库 binlog 的 position,后面可以用于增量同步:
    2023-07-30T10:54:20.071629Z 0 [Note] InnoDB: Last MySQL binlog file position 0 496, file name mysql-bin-changelog.052391
  • 对于 RDS mysql 8.0,暂时无法通过日志查找到快照建立时刻的数据库 binlog 的 position,所以如果想找到这个信息,可以在建立快照的时候,先停止所有业务访问或者修改对应参数组中的“read_only”为 1,保证数据库处于一个稳定状态,然后执行如下命令,此命令会刷新当前正在使用的二进制日志文件,并将其关闭,同时打开一个新的日志文件,以防有未刷新的 binlog:
    FLUSH BINARY LOGS;
  • 并且通过如下命令查看 binlog 的 position 用于后面的步骤:
    SHOW MASTER STATUS;
  • 所以如果数据库引擎版本是 5.7,那么实现此复制构架,源数据库不需要停止业务访问,但是如果是 8.0,想通过 binlog position 的方式做增量同步,确认 binlog position 的时候,源数据库一定要有停止业务的窗口,供大家参考。

快照共享

另一个账号能用数据库快照,需要源数据库进行快照共享,主要步骤如下:

  • 源账号共享快照给目标账号,Amazon RDS 控制台,点击左侧的“快照”菜单,选中刚才建立的快照,点击“操作”—“共享快照”

注意:如果源数据库是使用“(default)aws/rds”密钥加密,这里先需要使用上图中的“复制快照”选项先复制一个可以共享给其他账号的密钥来加密的快照,再把复制好的快照共享给其他账号,如下图所示:

点击“共享快照”后,如下图所示,输入目标账号的账户 12 位 ID,点击“添加”,然后保存即可:

  • 登录从库所在账号,打开 Amazon RDS 控制台,点击左侧的“快照”菜单,然后点击“与我共享”,“复制快照”,如下图所示:

然后输入快照的名称,复制快照即可。复制完毕之后,就可以看到在“手动”菜单下,已经有复制好的快照了。

在另一个账号中从快照恢复为实例

上面的步骤中,我们已经将快照共享给另一个账号了,只需要将快照恢复为数据库实例即可,选择复制好的快照,然后选择“还原快照”即可。

将快照还原为数据库的实例的时候,记得勾选日志选项,特别是错误日志,后面的步骤需要日志相关信息。

追加增量同步

通过上面的步骤,我们已经在另一个账号通过快照建立了一个数据库实例,可以认为全量数据已经复制到对端账号下,接下来需要进行增量的同步。

我们在源数据库上执行如下命令,得到测试数据表最新的数据:

select max(id) from drid;
+---------+
| max(id) |
+---------+
| 8827 |
+---------+
1 row in set (0.01 sec)

同样的,在从库上执行相同的命令,得到快照时候数据表当时的数据:

select max(id) from drid;
+---------+
| max(id) |
+---------+
| 122 |
+---------+
1 row in set (0.00 sec)

也就是说,id 为 123 以后的数据都需要追加同步,接下来我们需要验证同步是否成功。

增量同步方式一:采用基于 binlog position 的方式

此方式上文中解释过,RDS mysql 5.7 和 RDS mysql 8.0 获取的方式不一样。此时只需要在从库上执行如下的命令:

CALL mysql.rds_set_external_master ('mymasterserver.mydomain.com', 3306, 'repl_user', 'password', 'mysql-bin-changelog.000031', 107, 0);
CALL mysql.rds_start_replication;

然后可以执行如下命令查看复制状态

SHOW SLAVE STATUS\G;

此时我们在从库上执行如下命令来验证增量数据是否追加正确:

mysql> select * from drid where id=122;
+------+
| id |
+------+
| 122 |
+------+
1 row in set (0.00 sec)


mysql> select * from drid where id=123;
+------+
| id |
+------+
| 123 |
+------+
1 row in set (0.00 sec)

上面的结果可以看出,增量的数据已经开始同步了,而且是从断点开始同步的,而且没有重复数据被复制过来。

我们也可以在源数据库和从库反复执行如下命令,然后对比结果来判断增量数据是否持续不断的同步:

select max(id) from drid;
select count(*) from drid;

增量同步方式二:采用基于 GTID 的方式

在 mysql 8.0 上,如果不将源数据库保持在一个 read only 的状态下,我们暂时无法获取到 binlog 的准确 position 的位置,所以基于这个方式,那么源数据库如果是生产数据库,保证数据库处于 read only 的状态必将会影响或者停止业务,所以我们可以采用基于 GTID 的方式。

前文中关于 GTID 的参数我们已经预先准备好了,我们只需要通过如下命令来检查 GTID 是否启用:

SHOW GLOBAL VARIABLES LIKE 'gtid%';

基于 GTID 的复制,不需要定位 GTID 的位置,系统会自动定位断点位置并进行追加增量复制,只需要在从库上执行如下命令即可:

CALL mysql.rds_set_external_master_with_auto_position ('mymasterserver.mydomain.com', 3306, 'repl_user', 'password', 0, 0);
CALL mysql.rds_start_replication;

然后同样的,通过对比源数据库和从库的 drid 表来确定同步是否正常。

至此,整个同步关系就建立完成,而且复制关系是一直建立的,源数据库的增量数据会不断的复制到从库上。

写在最后

上面的实验步骤,我们已经建立了 Amazon RDS Mysql5.7/8.0 的跨账号的复制关系,这种方式也适用于外部数据源和 Amazon RDS mysql 之间的复制关系,可以作为容灾备份,也可以用于数据库迁移。我们能学习到的经验是:

  • 同引擎数据库的容灾或者迁移,使用数据库本身的功能来实现,即安全又高效。
  • 如果源数据库和目标数据库(从库)是不同引擎的,那么可能需要借助其他工具,比如 AWS DMS(Database Migration Service)来实现,这里就不做介绍了。

系列博客

本篇作者

王京来

亚马逊云科技解决方案架构师,目前专注于存储、数据库相关的解决方案。在加入 AWS 之前,曾就职于惠普、EMC 等科技公司,从事企业级用户 IT 基础架构相关工作,拥有二十余年技术服务经验。