亚马逊AWS官方博客

Aurora MySQL 2 升级之下游 Binlog 消费处理方案 – Canal CDC

Amazon Aurora 是专为云构建的一种兼容 MySQL 和 PostgreSQL 的关系数据库,它既具有传统企业数据库的性能和可用性,又具有开源数据库的精简性和成本效益。随着 2023 年 10 月 MySQL 社区停止对 MySQL 5.7 版本的支持,AWS 也将在 2024 年 10 月 31 日停止兼容 MySQL 5.7 的 Aurora MySQL 2 的支持工作,客户需要在停止支持时间之前将 Aurora MySQL 2 升级至 Aurora MySQL 3,否则将会对 Aurora MySQL 2 版本在停止支持时间点后自动开启延展支持,并在 2024 年 12 月 1 日开始对延展支持进行收费

在使用 MySQL 的过程中,部分用户会选择实时拉取 MySQL 的二进制日志 binlog 以供其他任务消费,其中比较常见的 Canal 是基于 Java 语言开发的一款提供增量数据订阅和消费工具。因为 Canal 是基于特定实例以及端口进行配置消费的工具,在 Aurora MySQL 2 升级到场景中,保持 Canal 正常的数据同步,也是很多客户关心问题。本文通过详细的步骤,演示了 Aurora MySQL 2(兼容 MySQL 5.7)通过蓝绿部署方式升级至 Aurora MySQL 3 后 Canal 的表现以及升级对 Canal 的影响。同时,对比基于普通 binlog 模式以及 GTID 模式下的 Canal 的不同表现,为客户对 Aurora 升级给 Canal 的影响作出正确的评估与处理给出参考。

Canal 简介

Canal 是一款开源的 MySQL 数据库增量日志解析工具,其模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送 dump 协议,进而获取并解析 binary log 对象,回放至目标端,提供增量数据订阅和消费。当前的 Canal 支持源端 MySQL 版本最高到 8.0.x 版本。

常见的基于日志增量订阅和消费的业务包括:

  • 数据库镜像
  • 数据库实时备份
  • 索引构建和实时维护(拆分异构索引、倒排索引等)
  • 业务 cache 刷新
  • 带业务逻辑的增量数据处理

Canal 1.1.1 版本之后, 增加了客户端数据落地的适配及启动功能。本文将使用 RDB Adapter 用于适配 Aurora MySQL 到关系型数据库 RDS MySQL 的数据同步及导入。下面是具体的演示步骤以及结果和分析。

场景演示

1. 数据库环境准备

通过 AWS 控制台,创建两个数据库:

  • 源数据库:

蓝环境:Aurora MySQL 2
绿环境:Aurora MySQL 3

  • 目标数据库:

RDS MySQL 8.0.35

本文我们会使用 Canal Server 以及 Canal Adapter 将源数据库的变更,同步到目标数据库。

1.1 源数据库环境准备

a)连接到数据库

mysql -haurora-57.cluster-***********.us-east-2.rds.amazonaws.com -u<your-username> -p<your-password

b)创建测试源表 users

CREATE DATABASE test_db;
USE test_db;
CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `ct_time` timestamp NOT NULL DEFAULT '2024-10-08 13:36:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.2 目标数据库环境准备

a)连接到数据库

mysql -hdatabase-2.***********.us-east-2.rds.amazonaws.com -u<your_username> -p<your-password>

b)创建测试目标表 users

CREATE DATABASE test_db;
USE test_db;
CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(10) NOT NULL,
  `ct_time` timestamp NOT NULL DEFAULT '2024-10-08 13:36:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

2. Canal Server 以及 Canal Adapter 环境准备

因本文主要演示 Aurora MySQL 2 升级过程中,Canal CDC 表现以及问题,所以以 EC2 为环境搭建 Canal 以及 Canal Adapter。

2.1 Canal Server 环境准备

a)下载 canal-1.1.7,解压到 canal 目录

mkdir canal
tar -xvf canal.deployer-1.1.7.tar.gz -C canal
cd canal

b)设置 canal serve

Instance.properties 文件

# master info
canal.instance.master.address=aurora-57.cluster-***********.us-east-2.rds.amazonaws.com:3306
# username/password
canal.instance.dbUsername= <canal_username>
canal.instance.dbPassword= <canal_password>
canal.instance.connectionCharset = UTF-8

2.2 Canal Adapter 环境准备

a)下载 Canal-Adapter-1.1.7 ,解压到 canal-adapter 目录

mkdir canal-adapter 
tar xf canal.adapter-1.1.7.tar.gz -C canal-adapter
cd canal-adapter

b)设置 RDS Adapter

application.yaml 文件

canalAdapters:
- instance: example # canal instance Name or mq topic name
groups:
- groupId: g1
    outerAdapters:
    - name: logger
    - name: rdb
    key: mysql1
    properties:
        jdbc.driverClassName: com.mysql.jdbc.Driver
        jdbc.url: jdbc:mysql://database-2.***********.us-east-2.rds.amazonaws.com:3306/test_db?useUnicode=true
        jdbc.username: <adapter_username>
        jdbc.password: <adapter_password>  

2.3 启动 Canal Server 以及 Canal Adapter

使用下面的命令启动 Canal Server 以及 Canal Adapter

cd canal
sh bin/startup.sh

cd canal-adapter
sh bin/startup.sh

netstat -tnlp | grep java
tcp        0      0 0.0.0.0:11110           0.0.0.0:*               LISTEN      1307/java           
tcp        0      0 0.0.0.0:11111           0.0.0.0:*               LISTEN      1307/java           
tcp        0      0 0.0.0.0:11112           0.0.0.0:*               LISTEN      1307/java           
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      1762/java  

3. 通过 Canal 进行数据同步

a)通过以下 python 函数在源端插入记录

def write_op(pool):
        try:
            conn = pool.connection()
            now=now_time()
            cur = conn.cursor()
            cur.execute('insert into users (name,ct_time) values("test_canal",now()) ON DUPLICATE KEY UPDATE ct_time=now();')
            conn.commit()
            cur.close()
            conn.close()
            print ("%s [INFO] Request execute successful: /*Write*/ insert finished." %(now))

b)在源端与目标端分别查询数据,确认数据同步无误

#源端
MySQL [test_db]> select * from users;
+----+------------+---------------------+
| id | name        | ct_time                 |
+----+------------+---------------------+
|  1 | test_canal | 2024-10-10 13:10:24 |
|  2 | test_canal | 2024-10-10 13:11:05 |
|  3 | test_canal | 2024-10-10 13:15:35 |
+----+------------+---------------------+
3 rows in set (0.000 sec)

#目标端
MySQL [test_db]> select * from users;
+----+------------+---------------------+
| id | name        | ct_time                |
+----+------------+---------------------+
|  1 | test_canal | 2024-10-10 13:10:24 |
|  2 | test_canal | 2024-10-10 13:11:05 |
|  3 | test_canal | 2024-10-10 13:15:35 |
+----+------------+---------------------+
3 rows in set (0.000 sec)

4. 普通 Binlog 模式下蓝绿切换 Canal CDC 的表现

我们需要关注的是:

  • 蓝绿环境切换中,Canal CDC 同步状态
  • 蓝绿部署切换后,Canal Server 的状态
  • 蓝绿部署切换后,Canal Adapter 的状态
  • 蓝绿部署切换中,数据消费处理是否正常

4.1 分步测试

a)确认蓝绿切换前 Canal Server 以及 Canal Adapter 状态正常,启动 1 步骤中数据插入脚本,每秒插入一行数据,完成后进行蓝绿部署切换

b)确认蓝绿切换完成后,确认切换后日志信息以及表数据是否一致

Aurora MySQL 蓝绿切换位点信息:

源端和目标端数据状态:

# 源端与目标端一致
MySQL [test_db]> select  count(*) from users;
+----------+
| count(*) |
+----------+
|      345 |
+----------+
1 row in set (0.003 sec)

c)根据蓝绿切换记录的日志位点信息确认切换后的消费起始数据

svr/mysql80/bin/mysqlbinlog --read-from-remote-server --host=aurora-57.cluster-************.us-east-2.rds.amazonaws.com --port=3306 --user admin --password --raw   --verbose    --result-file=/tmp/  mysql-bin-changelog.000008
 
 svr/mysql80/bin/mysqlbinlog -vvv /tmp/mysql-bin-changelog.000008|more

d)蓝绿切换完成后确认 Canal Adapter 状态以及 Canal Server 状态

经输出日志可知蓝绿切换中断时间为 2024-10-10 13:30:33 ~ 2024-10-10 13:30:54

查看该时间段内 Canal Server 以及 Canal Adapter 的状态,相关日志输出信息如下:

Canal Server 端 example.log 切换时内容:

2024-10-10 13:31:04.276 [destination = example , address = aurora-57.cluster-*************.us-east-2.rds.amazonaws.com/172.31.32.119:3306 , EventParser] WARN  c.a.o.c.p.inbound.mysql.rds.RdsBinlogEventParserProxy - ---> find start position successfully, EntryPosition[included=false,journalName=mysql-bin-changelog.000008,position=12409,serverId=144983857,gtid=,timestamp=1728566746000] cost : 11ms , the next step is binlog dump

Canal Adapter 端 adapter.log 切换时内容:

经过日志分析可知,Canal Server 在蓝绿切换期间因域名无法连接导致报错并重试,在实例恢复后开始继续消费,且起始位点为 mysql-bin-changelog.000008 position=12409,Canal adapter 状态无影响,切换前同步的最后一条记录为 id 为 57,切换完成后起始消费记录 id 为 8,查看对应 binlog 日志位点,如下图,再次消费起始位点与起始消费记录相符,表明 adapter 在蓝绿切换之后存在 binlog 重复消费行为。但是因为 adapter 的同步依然认为消费成功。所以这里切换完成后能保证数据一致且 adapter 无报错。

下图为 mysql-bin-changelog.000008 日志 position 为 12409 的详细信息:

进一步确认 Canal 相关代码可知,Canal 在处理源节点切换时,确实会存在一个 60 秒钟的回退时间。这里如果 binlog 的消费端为非 rds adapter 的其他组件,则需要注意幂等处理。

 {
            long newStartTimestamp = logPosition.getPostion().getTimestamp() - fallbackIntervalInSeconds * 1000;
            logger.warn("prepare to find start position by switch {}:{}:{}", new Object[] { "", "",
                    logPosition.getPostion().getTimestamp() });
            return findByStartTimeStamp(mysqlConnection, newStartTimestamp);
        } 

# mysql fallback connected to new master should fallback times
canal.instance.fallbackIntervalInSeconds = 60

5. GTID 模式下蓝绿切换 Canal CDC 表现

所有 RDS for MySQL 5.7 版本、RDS for MySQL 版本 8.0.26 及更高的 MySQL 8.0 版本均支持基于 GTID 的复制。在复制配置中,GTID 在所有数据库实例中是唯一的。GTID 简化了复制配置,因为在使用它们时,您不必引用日志文件位置。通过使用 GTID,还可以更轻松地跟踪复制的事务并确定源实例和副本是否一致。Canal 也支持 GTID 模式下的 binlog 复制,我们将通过以下过程,演示 GTID 模式下 Canal 消费 binlog 的表现。

5.1 修改实例参数组为 GTID 模式

通过参数组开启 Aurora MySQL 2 中的 GTID 设置,注意该参数为静态参数,修改配置后需重启

enforce_gtid_consistency = ON
gtid-mode = ON

5.2 修改 Canal 基于 GTID 模式消费

参数修改重启实例应用该参数后,修改 Canal 配置 instance.properties,重启 Canal 进行基于 GTID 模式的 binlog 消费

canal.instance.gtidon=true

如果需要在现有普通 binlog 模式转换为 GTID 模式进行 binlog 消费,可以参考以下调整步骤可实现不停业务写入修改 Canal 的 Binlog 消费模式,如果能停写业务,则可以在业务停写后,对 Canal 进行 GTID 模式调整后,由 Canal 进行最新位点的继续同步工作。

1)Aurora MySQL 2 开启 GTID 功能,重启数据库集群
2)Canal 暂停消费,停止 Canal Server
3)根据 meta.log 中的 binlog position 找到 binlog 中对应的 GTID
4)根据 GTID 配置对应位点信息
5)删除 Canal meta.data 后启动 Canal Server

5.3 调整完成后分步测试

a)确认蓝绿切换前,canal server 消费正常,且源端和目标端数据一致

#源端与目标端数据一致
MySQL [test_db]>  select count(*) from users;
+----------+
| count(*) |
+----------+
|       60   |
+----------+
1 row in set (0.001 sec)

确认蓝绿切换前 Canal Server 以及 Canal Adapter 状态正常,后启动 2.1 步骤中数据插入脚本,每秒插入一行数据,完成后进行蓝绿部署切换。

b)确认切换完成后,确认切换后日志信息以及表数据是否一致

Aurora MySQL 蓝绿切换位点信息:

源端和目标端数据状态:

# 源端与目标端一致
MySQL [test_db]> select count(*) from users;
+----------+
| count(*) |
+----------+
|      258 |
+----------+
1 row in set (0.002 sec)

c)根据蓝绿切换记录的日志位点信息确认切换后的消费起始数据

svr/mysql80/bin/mysqlbinlog --read-from-remote-server --host=aurora-57-enable-gtid.cluster-************.us-east-2.rds.amazonaws.com --port=3306 --user admin --password --raw   --verbose    --result-file=/tmp/  mysql-bin-changelog.000009
 
 svr/mysql80/bin/mysqlbinlog -vvv /tmp/mysql-bin-changelog.000009|more

d)切换完成后确认 Canal Adapter 状态以及 Canal Server 状态

确认中断时间端

经输出日志可知蓝绿切换中断时间为 2024-10-11 05:29:52~ 2024-10-11 05:30:14

查看该时间段内 Canal Server 以及 Canal Adapter 的状态信息:

Canal Server 端 example.log 切换时内容:

Canal Adapter 端 adapter.log 切换时内容:

原绿集群最后一条日志文件 mysql-bin-changelog.000004 中位点 position 为 104779 对应的位点信息如下:

经过日志分析可知,Canal Server 在蓝绿切换期间因域名无法连接导致报错并重试,在实例恢复后开始继续消费,且最后一次消费位点为 mysql-bin-changelog.000004,position=104779,gtid=ab0efaf0-b79d-3ad5-8c7d-a2fc761a4f49:1-367,切换前同步的最后一条记录为 id 为 76,切换完成后起始消费记录 id 为 77,查看对应 binlog 日志位点,位点与记录相符,表明 GTID 模式下 Adapter 在蓝绿切换之后存在 binlog 消费行为正常。

总结

本文通过详细的步骤演示了 Aurora MySQL 2(兼容 MySQL 5.7)通过蓝绿部署方式升级至 Aurora MySQL 3 后,binlog 消费组件 Canal 的表现以及通过蓝绿部署进行升级过程中,蓝绿切换对 Canal 的影响。同时,对比了基于普通 binlog 模式以及 GTID 模式下的 Canal 的不同表现,为客户对 Aurora MySQL 2 升级给 Canal 的影响作出正确的评估与处理给出参考。通过演示过程得知,普通 binlog 模式下,实例的切换会导致 Canal 消费位点后退一定时间端,通常为 60 秒,会造成部分重复 binlog 的同步,注意在目标端幂等处理。在 GTID 模式下,较好地避免了重复消费的情况,但是 GTID 模式下,Canal 能在切换造成 Canal 中断后更好地处理位点的衔接,做到无遗漏无重复。客户可以在实际使用 Canal 的过程中,结合具体场景以及需求,评估是否需要使用 GTID 模式进行 Canal CDC 任务。

本篇作者

李芬芳

亚马逊云科技数据库专家,负责亚马逊云科技数据库相关的架构优化、成本管理、技术咨询等工作。加入 AWS 之前曾就职于腾讯、唯品会、圆通速递等公司,有多年数据库管理经验。

高文成

亚马逊云科技技术客户经理,负责 AWS 企业级客户的架构设计和优化、成本管理和技术咨询。在加入亚马逊云科技之前,曾就职于甲骨文,负责为航空、互联网等行业客户进行云上解决方案规划和咨询服务。专注于数据平台架构和数据库系统研究。