AWS Database Blog
Create a fallback migration plan for your self-managed MySQL database to Amazon Aurora MySQL using native bi-directional binary log replication
In the age of agile development and automated cloud deployment, most relational database migrations still must follow a sequential approach. It is common for a single database to support multiple applications or modules and involve multiple teams. Usually, all applications must move together at the same time. If you’re planning to migrate to Amazon Aurora MySQL-Compatible Edition from a self-managed MySQL environment on premises or on Amazon Elastic Compute Cloud (Amazon EC2), you may be looking for a simpler fallback mechanism or a way to migrate applications incrementally.
In this post, we show you how to set up bi-directional replication between an on-premises MySQL instance and an Aurora MySQL instance. We cover how to configure and set up bi-directional replication and address important operational concepts such as monitoring, troubleshooting, and high availability. In certain use cases, native bi-directional binary log replication can either provide a simpler fallback plan for your migration or provide a way to migrate applications or schemas individually, rather than all at the same time.
Three use cases for bi-directional replication
If your MySQL deployment is for a single application or you have a monolithic workload with many dependencies between components, you can use bi-directional replication for a simplified fallback plan. With database changes flowing in both directions, if something unexpected happens during the migration to Amazon Aurora, you can quickly redirect applications to the original source database.
Additionally, bi-directional replication can facilitate an incremental multi-tenant migration. A multi-tenant MySQL deployment contains a schema or database for each customer or tenant. After bi-directional replication is established between the self-managed database and Aurora, it may be possible to migrate each tenant separately.
Lastly, your MySQL deployment may support multiple applications that use mutually exclusive sets of tables or separate schemas. In this case, each application may be migrated separately.
Considerations for bi-directional replication
Bi-directional replication is based on MySQL native binary log replication. Native replication in MySQL is asynchronous. There can be replication lag between the source and target. There is no built-in conflict resolution in native MySQL replication. Therefore, it is not recommended to write data to the same tables on both sides of a bi-directional replication. Doing so may result in errors that cause replication to stop in one or both directions. Both servers could contain different data. This is commonly referred to as split brain. A basic explanation can be found in Split Brain 101: What You Should Know. In our test scenario in this post, we mitigate insertion collisions by setting the auto_increment_increment and auto_increment_offset variables. Simultaneous deletions or updates can still cause problems that are difficult to reconcile.
Troubleshooting MySQL replication is a time-consuming process that may include manual data inspection and verification, and manual data changes such as manual inserts, updates, or deletions. Manual skipping of transactions in MySQL or manual skipping of transactions in Aurora may also be necessary.
During the migration process, make sure that all processing for each schema or each application is fully stopped. Verify that the configuration for the application is changed to the new target before restarting the application.
Solution overview
The following diagram illustrates the architecture specific to this post.
The steps to enabling bi-directional replication are as follows:
- Enable binary logs on the on-premises MySQL instance.
- Create a custom Aurora parameter group with parameters necessary to enable binary logs on the cluster.
- Back up your source database and restore it to Aurora using one of the available migration options. We use Percona Xtrabackup in this example, and we copy the resulting files to an Amazon Simple Storage Service (Amazon S3) bucket. For more details, see Physical migration from MySQL by using Percona Xtrabackup and Amazon S3.
- Configure bi-directional replication.
- Validate replication status.
- Optionally, test bi-directional replication during an Aurora high availability failover event.
Please note the Limitations and recommendations for importing backup files from Amazon S3 to Amazon RDS and Replication Compatibility Between MySQL versions. A supported bi-directional replication will be between equal major versions.
The screenshots in this post use MySQL 5.7 and Aurora version 2. The same procedure has been tested on MySQL 8.0 and Aurora version 3.
Prerequisites
The sample solution requires an existing on-premises database instance or existing database instance on Amazon EC2. The sample solution also requires that you have a set of networking resources in place, such as the following:
- A VPC
- Network connectivity:
- A database security group
- AWS Virtual Private Network (AWS VPN) or AWS Direct Connect providing private IP connectivity from the source database instance to Aurora.
Enable binary logs on the on-premises MySQL instance
To configure the following parameters to enable binary logs on the on-premises MySQL instance, add the following lines in the /etc/my.cnf
configuration file.
Because log_bin is a static variable, you must restart MySQL to enable the binary log. Note that the parameters set here will match the parameters set in Aurora in the next step. We want all of the binary log related parameters to be the same, with one exception. The auto_increment_increment will be different, so that auto-incrementing integer values written on the on-premises server will be even numbers, and auto-incrementing integer values written on Aurora will be odd numbers.
You can set expire_logs_days (MySQL 5.7) or binlog_expire_logs_seconds (MySQL 8.x) to a higher value, if needed. The larger your database and the longer the restore time, the more binary logs you will need in order to successfully set up binary log replication.
For more information, see Binary Logging Options and Parameters.
Create a custom Aurora parameter group
In Aurora, there are two types of parameter groups: cluster level and instance level. Binary log parameters are only available in a cluster-level parameter group. To set custom values for the required parameters, you must create a custom cluster-level parameter group. Refer to Working with DB cluster parameter groups for more details. You use this custom parameter group in a later step when you restore a new Aurora cluster from your backup in Amazon S3.
The parameters to modify are as follows:
You can verify the configuration changes on the Amazon RDS console. On the Parameter groups page, select your newly created parameter group and on the Actions menu, choose Compare.
Check the new parameter group values against the original default in order to confirm the configuration changes.
Back up the source database
There are several ways to back up the source database and restore to an Aurora MySQL cluster. For this post, we take a backup of the source database using the Percona XtraBackup tool. The following code is an example of how to back up a database on premises or on Amazon EC2:
The backup file is created in the /opres
directory. It’s important to confirm that the backup completed successfully by looking for the completed OK message at the end of the log file.
You can use the AWS Command Line Interface (AWS CLI) or the AWS SDK to transfer the backup contents to Amazon S3. For example, an AWS CLI command can synchronize all the contents of the /opres
directory into your bucket:
Restore the backup to an Aurora database
After a consistent database full backup is stored in your S3 bucket, you can perform the restore.
- On the Amazon RDS console, choose Databases in the navigation pane.
- Choose Restore from S3.
- For S3 bucket, enter the bucket where the backup files are stored.
- For Engine type¸ select Aurora (MySQL Compatible).
- For Available versions, choose the version that most closely matches your on-premises database. For this example, we choose Aurora (MySQL 5.7) 2.11.2.
- For IAM role, choose an appropriate AWS Identity and Access Management (IAM) role with permissions to do the restore, or create a new role.
- For Availability & durability, select Create an Aurora Replica or Reader node in a different AZ (recommended for scaled availability).
- Expand the Additional configuration section under Database options.
- For DB cluster parameter group, choose the custom parameter group you created in the previous section of this post.
- Complete the other options to finish the restore configuration, then choose Create database. When the database is ready, its status will show as Available.
- Select the new cluster and verify the parameter group on the Configuration tab.
Configure bi-directional replication
At this point, both the on-premises MySQL instance and the Aurora MySQL instance are ready for replication to be enabled. Connect to both instances with a privileged user and create the replication user accounts. You can get the cluster writer endpoint from the Amazon RDS console on the Connectivity & security tab.
- Connect to your on-premises MySQL instance.
- Run the following commands to create the replication user:
- Configure the Aurora MySQL instance as a replica of the on-premises MySQL database. When this is complete and replication is started, the user you created will be replicated to Amazon Aurora MySQL, along with any other changes. On Amazon Aurora MySQL, call the command mysql.rds_set_external_master_with_auto_position:
- Start the Aurora replication with the command CALL
mysql.rds_start_replication
against the Aurora MySQL database. Consider adjusting the retention of the binary log files in Aurora for at least 2 days with the command CALLmysql.rds_set_configuration(‘binlog retention hours’, 48);
. - Configure the on-premises MySQL instance as a replica of the Aurora MySQL instance:
- Finally, run
start slave;
to start replication.
You have now established replication in both directions. We check the replication status in the next section.
Refer to Migrating data from an external MySQL database to an Amazon Aurora MySQL DB cluster for additional specifics.
Validate replication status
To make sure that replication is configured correctly, run the command show slave status\G
to confirm that each MySQL database has the correct Master_Host
information and that the settings Slave_IO_Running
and Slave_SQL_Running
are both showing yes. Make sure that there are no errors listed in this output by examining the Last_Errorno
and Last_error
fields. Run the command repeatedly to monitor Seconds_Behind_Master
to verify that this value approaches 0 over time. The following is an example terminal output:
Running the show slave status\G
command against the Aurora MySQL instance should output something similar to the preceding code.
You can also validate replication lag status by using the Amazon CloudWatch metric AuroraBinLogReplicaLag
. If replication is not running, there will be no line. If replication is running behind, this metric will show a non-zero number of seconds. If replication is caught up, the graph will display 0 seconds.
Test bi-directional replication during an Aurora high availability failover event
High availability for Aurora DB instances provides a failover mechanism when the primary instance encounters a problem. An Aurora reader instance takes over as the primary instance. To test high availability in an AWS Region, you can manually invoke a failover event via the Amazon RDS console to promote the read replica. In this test, we invoke the failover while inserting 1,000 rows every 2 seconds.
For this example, we create a persona table in both databases and start the test with 537,384 rows in each table.
In the following example, we start the script to insert data into both databases (terminal 1):
Terminal 2 shows us that bi-directional replication is working by incrementing the row counts on both sides:
After we confirm that bi-directional replication is working as expected, we can invoke a failover from the Amazon RDS console. Select the writer instance and on the Actions menu, choose Failover.
Seconds later, the Aurora inserts fail as expected (terminal 1), but the inserts into the on-premises MySQL database continue without error:
In the Terminal 2, we can see that while the failover is taking place, our count queries are also failing with connection errors:
On the Amazon RDS console, you can validate the failover and see that the instance cl-mysqlop-instance-2 is now the writer instance.
The failover should occur in seconds. If we monitor the script, we can see that the errors clear up quickly and shortly thereafter, the bi-directional replication synchronizes any changes, and both tables have matching row counts of 605,384 rows.
The following is the view in terminal 1:
The following is the view in terminal 2:
Counting rows in table persona
on-premises
With this test, we can confirm that the Aurora cluster is able to maintain synchronization with the on-premises MySQL instance after a failover event without any manual intervention. Failover and binary log synchronization times can vary depending on the write activity and the number of unapplied records in the binary logs.
Clean up
To avoid incurring future charges, delete any resources that you created as part of this post, such as the following:
- VPC
- Database subnet group
- Database security group or security group rules
- AWS VPN connection
- Aurora cluster
- S3 bucket
- EC2 instance
Conclusion
In this post, we demonstrated how to configure bi-directional replication from an on-premises MySQL or EC2 instance to an Aurora MySQL instance. We showed that bi-directional replication self-heals and continues successfully during a high availability failover within the same Region, without the need for manual intervention.
Bi-directional replication is one solution that may provide organizations with flexibility and reduced risk when migrating to Amazon Aurora MySQL. We encourage you to refer to Working with Amazon Aurora MySQL and learn about the other capabilities of Amazon Aurora MySQL that can help transform your organization.
About the Authors
Elkin González is a Sr. Database Specialist Solutions Architect at AWS located in Bogotá, Colombia. He has expertise in RDBMS and cloud technologies, with over 15 years of experience working for high-tech companies such as IBM and Thales. He is currently helping partners and organizations in Latino América design, modernize, and adopt AWS database cloud services. In his spare time, he loves spending time with family, friends, and his dog.
John Scott is a Sr. Database Specialist Solutions Architect based in Atlanta. He has years of experience as a Linux Admin and DBA for companies of all sizes. John’s favorite things are family, great barbecue, and Amazon Aurora.