AWS Database Blog
Upgrade Amazon RDS for MySQL or MariaDB database schemas with minimal downtime
Modifying the schema of an SQL database can be time-consuming, resource-intensive, and error-prone, and often requires long application maintenance windows that negatively affect the end-user experience. Amazon Relational Database Service (Amazon RDS) for MySQL or MariaDB allows you to upgrade your schema while your application is still running, with minimal or zero downtime. In this post, I walk you through the process of using an RDS for MySQL or MariaDB replica to perform a schema update on a database without negatively affecting the user experience.
The solution uses an Amazon RDS for MySQL version 8.0 database, but you can easily modify it to use other MySQL or MariaDB versions, as needed.
The cost of implementing the solution is equal to the cost of running additional RDS replicas for the time needed to perform the schema change. For more information, see Amazon RDS Pricing.
NOTE: This solution doesn’t necessarily eliminate downtime, but it can reduce it dramatically for very large databases, and for complicated schema changes. The procedure mentions when read-only mode for your application begins and ends. During this window, it’s important that your application deal with read-only databases gracefully, for example by telling customers that their data is read-only during the maintenance window. It’s also important that you streamline the testing phase to run as quickly as possible, without sacrificing test accuracy and coverage.
Get started
I strongly recommend you test this solution in a sandbox environment several times until you’re comfortable attempting it in a production environment.
This post explains how to implement this procedure using the AWS Command Line Interface (AWS CLI), which allows you to interact with the AWS control plane from a Linux, UNIX, Windows, or Macintosh shell, or the AWS CloudShell. You can also perform the steps via the AWS Management Console, if you prefer.
Create the required parameter groups
You need two parameter groups: one for the source, and one for the target. You can’t use the default parameter groups because the default parameter groups can’t be modified, and you need to make changes to the read_only
parameter during this process. Run the following CLI commands.
After those commands are complete, the architecture looks like the following diagram.
Create the source database
NOTE: If you already have an RDS database to use as the source database, you can skip this step and use that database’s information instead. However, the source database must be attached to a custom parameter group that isn’t attached to any other databases. If your source database uses the default parameter group, or a parameter group that is shared with other databases, you must attach the parameter group you created in the previous step to the source database before you begin. Attaching a custom parameter group to a database requires a reboot, so your should do this during a normal RDS maintenance window to minimize impact on your application.
To create a suitable RDS database, use the following CLI command.
Then wait for the RDS database to be available.
When the RDS instance is available, obtain its endpoint name.
Now you can connect to the RDS instance using its endpoint address.
Now the architecture looks like the following diagram.
At this point, if you want to test this solution against your actual application schema, you should load it and the associated application data into the RDS database you created. Otherwise, continue with the following steps.
Create a test table and insert some test data.
Now let’s insert a row of data into the schema:
To make things slightly more interesting, you can increase the amount of data in the table exponentially by running the following query a few times.
You can repeat the insert statement as many times as you like. Each time you run the query, you double the number of rows in the database. After 16 runs, you should have 2^16 or 32,768 rows. After 24 runs, you should have 2^24 or 16,777,216 rows. Any number of rows is enough for this experiment, but larger databases take longer to upgrade, and so this solution is more impactful for those. To find out how many rows you have in your table, you can run the following query.
Create the target database
Create a replica database from the source.
Wait for the instance to become available.
Attach the database parameter group to the replica.
Reboot the replica so that it picks up the new parameter group immediately.
Wait for it to become available again.
When the replica database is available, obtain its endpoint address.
At this point, queries to the read replica will return the same data that queries to the primary return.
Once the target-database comes on-line, the architecture looks like the following diagram.
Upgrade the schema
Now that you have a writable replica up and running, you can modify the schema on it.
The SQL statements that you use to modify the schema will vary according to your application and upgrade path. The following examples are very simple, and can take anywhere from less than 1 second up to several minutes or even hours, depending on how many rows you inserted into the database during setup.
There are two possible paths.
- The schema changes are fully backward-compatible
- The schema changes have backward-incompatible changes
In this context, backward-compatible means that the changes won’t break replication. For example, adding a new column, increasing the size of an existing column, or adding or removing indexes, are all generally backward-compatible. Operations such as dropping columns, changing column names or types, reducing the size of an existing column, or adding new foreign keys, are potentially backward-incompatible. A qualified database administrator (DBA) can identify which of these cases applies to your upgrade.
Schema updates that include backward-incompatible changes will result in longer read-only periods during the schema change process. To the maximum extent possible, try to make your schema changes backward-compatible for this reason. If you must perform a backward-incompatible schema change, consider breaking it up into two separate upgrades: one that is backward-compatible, and one that is backward-incompatible, so that the read-only time period is minimized.
If you’re using your actual application schema and data, you need to replace the following SQL statements with those that actually upgrade your database.
Backward-compatible schema changes
If your schema changes are backward-compatible, follow these steps.
Connect to the target-database
.
Upgrade the schema.
When the schema change on the target-database
is complete, make the source-database
read-only by modifying its parameter group.
This change takes a few minutes to complete. You can check to see if it has completed by running the following query on the source-database
.
NOTE: From this point on until the end of the procedure, the application is in read-only mode.
Backward-incompatible schema changes
If your schema changes are backward-incompatible, follow these steps.
Stop all updates on the source-database
by modifying its parameter group.
This change takes a few minutes to complete. You can check to see if it has completed by running the following query on the source-database
.
NOTE: From this point on until the end of the procedure, the application is in read-only mode.
Next, log into the target-database
to upgrade the schema.
Upgrade the schema.
Review the architecture
Now that you have modified the parameters for the source-database, the architecture looks like the following diagram.
At this point, your application is still accessing source-database
in read-only mode, and you promote the target-database
to a standalone instance so that you can perform testing and validation against it. Your application should be architected so that it returns a user-friendly message letting people know that it’s currently in read-only mode.
Promote the replica to a stand-alone database
Promote the replica to a stand-alone database.
Wait for the instance to become available.
NOTE: This doesn’t reconfigure source-database
to be a replica. This command splits the databases into two independent databases.
When the promotion is complete, the architecture looks like the following diagram.
Create additional read replicas, if needed
If your original database had read replicas, you need to add read replicas to the target-database at this point. For example, if you had three read replicas on the source-database
, you should probably create three read replicas on target-database
. If your schema change increases database efficiency, you might be able to create fewer replicas on the target-database
. On the other hand, if your schema changes introduce new complexity that requires more processing power, you might need to create more than three replicas on the target-database
.
How many replicas you require depends on the application. Your developers and DBAs should be able to determine how many replicas are required for the target-database
. When in doubt, I recommend that you overprovision read replicas initially, and scale back when you’re confident in your application’s performance.
Test, test, test
Perform whatever testing is necessary against the target-database
to validate that the schema has been successfully migrated. This step is application specific, and what tests are required and how long they take depend on the specifics of your workload.
If your tests fail, you can either repair the schema on the target-database
manually, or terminate the target-database
, modify your upgrade procedure, and start again. If you choose to terminate the target-database
and revert back to the source-database
, you must change the parameter group on the source-database
to permit writes again.
Switch to the target database
After the new schema is validated and the necessary replicas have been created, reconfigure the application to use the target-database
endpoint, and validate that the application is still performing correctly. If you’re using the Amazon RDS Proxy, make your changes in the proxy configuration instead of your application configuration. Using Amazon RDS Proxy may reduce connection errors that your application sees during the transition to the target-database
.
Cleaning up
To remove all the resources you created during this walk-through, use the following commands.
Summary
With the solution outlined in this post, you can reduce or eliminate application down-time associated with database schema changes in Amazon RDS for MySQL and MariaDB. The steps described in this solution allow you to make database schema changes with reduced impact to your application, improving the end-user experience and reducing the burden of database schema changes.
You can use a similar process to upgrade RDS MySQL and MariaDB databases across different major versions, for example upgrading a MySQL 5.7 database to MySQL 8.0. For more information, see Best practices for using a MySQL read replica to upgrade an Amazon RDS for MySQL database. For more information about MySQL replication on Amazon RDS, see Working with MySQL replication in Amazon RDS.
About the author
Tim Gustafson is a Senior Database Specialist Solutions Architect working primarily with open-source database engines.