Zoals we eerder zagen, kan het voor bedrijven een uitdaging zijn om hun gegevens uit RDS voor MySQL te halen. In het eerste deel van deze blog hebben we je laten zien hoe je je doelomgeving op EC2 instelt en een proxylaag (ProxySQL) invoegt tussen je applicaties en RDS. In dit tweede deel laten we u zien hoe u de daadwerkelijke migratie van gegevens naar uw eigen server uitvoert en uw applicaties vervolgens zonder downtime omleidt naar de nieuwe database-instantie.
Gegevens kopiëren uit RDS
Zodra we ons databaseverkeer via ProxySQL hebben laten lopen, kunnen we beginnen met de voorbereidingen om onze gegevens uit RDS te kopiëren. We moeten dit doen om replicatie op te zetten tussen RDS en onze MySQL-instantie die op EC2 draait. Zodra dit is gebeurd, zullen we ProxySQL configureren om verkeer van RDS om te leiden naar onze MySQL/EC2.
Zoals we in de eerste blogpost in deze serie hebben besproken, is de enige manier om gegevens uit de RDS te halen, via logische dump. Zonder toegang tot de instantie kunnen we geen hot, fysieke back-uptools zoals xtrabackup gebruiken. We kunnen ook geen snapshots gebruiken, omdat er geen andere manier is om iets anders te bouwen dan een nieuwe RDS-instantie van de snapshot.
We zijn beperkt tot logische dump-tools, daarom zou de logische optie zijn om mydumper/myloader te gebruiken om de gegevens te verwerken. Gelukkig kan mydumper consistente back-ups maken, zodat we erop kunnen vertrouwen om binlog-coördinaten te leveren waarmee onze nieuwe slaaf verbinding kan maken. Het belangrijkste probleem bij het bouwen van RDS-replica's is het binlog-rotatiebeleid - logische dump en laden kan zelfs dagen duren voor grotere (honderden gigabytes) datasets en u moet gedurende dit hele proces binlogs op de RDS-instantie bewaren. Natuurlijk kunt u de retentie van binlog-rotatie op RDS verhogen (bel mysql.rds_set_configuration('binlog retentie-uren', 24); - u kunt ze tot 7 dagen bewaren), maar het is veel veiliger om het anders te doen.
Voordat we doorgaan met het nemen van een dump, zullen we een replica toevoegen aan onze RDS-instantie.
Amazon RDS-dashboard Replica-DB maken in RDSZodra we op de knop "Leesreplica maken" klikken, wordt een momentopname gestart op de "master" RDS-replica. Het zal worden gebruikt om de nieuwe slaaf te voorzien. Het proces kan uren duren, het hangt allemaal af van de volumegrootte, wanneer was de laatste keer dat een momentopname werd gemaakt en de prestaties van het volume (io1/gp2? Magnetisch? Hoeveel pIOPS heeft een volume?).
Master RDS-replicaWanneer de slave gereed is (de status is gewijzigd in "beschikbaar"), kunnen we erop inloggen met behulp van het RDS-eindpunt.
RDS-slaafAls we eenmaal zijn ingelogd, stoppen we met replicatie op onze slave - dit zorgt ervoor dat de RDS-master geen binaire logs opschoont en dat ze nog steeds beschikbaar zijn voor onze EC2-slave zodra we ons dump-/herlaadproces hebben voltooid.
mysql> CALL mysql.rds_stop_replication;
+---------------------------+
| Message |
+---------------------------+
| Slave is down or disabled |
+---------------------------+
1 row in set (1.02 sec)
Query OK, 0 rows affected (1.02 sec)
Nu is het eindelijk tijd om gegevens naar EC2 te kopiëren. Eerst moeten we mydumper installeren. Je kunt het krijgen van github:https://github.com/maxbube/mydumper. Het installatieproces is vrij eenvoudig en mooi beschreven in het leesmij-bestand, dus we zullen het hier niet behandelen. Hoogstwaarschijnlijk zult u een aantal pakketten moeten installeren (vermeld in de readme) en het moeilijkere is om te bepalen welk pakket mysql_config bevat - dit hangt af van de MySQL-smaak (en soms ook de MySQL-versie).
Zodra je mydumper hebt gecompileerd en klaar voor gebruik, kun je het uitvoeren:
[email protected]:~/mydumper# mkdir /tmp/rdsdump
[email protected]:~/mydumper# ./mydumper -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com -p tpccpass -u tpcc -o /tmp/rdsdump --lock-all-tables --chunk-filesize 100 --events --routines --triggers
.
Let op --lock-all-tables die ervoor zorgt dat de momentopname van de gegevens consistent zal zijn en het mogelijk zal zijn om het te gebruiken om een slaaf te maken. Nu moeten we wachten tot mydumper zijn taak heeft voltooid.
Er is nog een stap nodig - we willen het mysql-schema niet herstellen, maar we moeten gebruikers en hun subsidies kopiëren. Daar kunnen we pt-show-grants voor gebruiken:
[email protected]:~# wget http://percona.com/get/pt-show-grants
[email protected]:~# chmod u+x ./pt-show-grants
[email protected]:~# ./pt-show-grants -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com -u tpcc -p tpccpass > grants.sql
Voorbeeld van pt-show-grants kan er als volgt uitzien:
-- Grants for 'sbtest'@'%'
CREATE USER IF NOT EXISTS 'sbtest'@'%';
ALTER USER 'sbtest'@'%' IDENTIFIED WITH 'mysql_native_password' AS '*2AFD99E79E4AA23DE141540F4179F64FFB3AC521' REQUIRE NONE PASSWORD EXPIRE DEFAULT ACCOUNT UNLOCK;
GRANT ALTER, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TEMPORARY TABLES, CREATE USER, CREATE VIEW, DELETE, DROP, EVENT, EXECUTE, INDEX, INSERT, LOCK TABLES, PROCESS, REFERENCES, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SELECT, SHOW DATABASES, SHOW VIEW, TRIGGER, UPDATE ON *.* TO 'sbtest'@'%';
Het is aan jou om te kiezen welke gebruikers moeten worden gekopieerd naar je MySQL/EC2-instantie. Het heeft geen zin om het voor iedereen te doen. Root-gebruikers hebben bijvoorbeeld geen 'SUPER'-privilege op RDS, dus het is beter om ze helemaal opnieuw te maken. Wat u moet kopiëren, zijn subsidies voor uw toepassingsgebruiker. We moeten ook gebruikers kopiëren die worden gebruikt door ProxySQL (proxysql-monitor in ons geval).
Gegevens invoegen in uw MySQL/EC2-instantie
Zoals hierboven vermeld, willen we geen systeemschema's herstellen. Daarom zullen we bestanden die verband houden met die schema's uit onze map mydumper verplaatsen:
[email protected]:~# mkdir /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/mysql* /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/sys* /tmp/rdsdump_sys/
Als we hiermee klaar zijn, is het tijd om gegevens in de MySQL/EC2-instantie te laden:
[email protected]:~/mydumper# ./myloader -d /tmp/rdsdump/ -u tpcc -p tpccpass -t 4 --overwrite-tables -h 172.30.4.238
Houd er rekening mee dat we vier threads (-t 4) hebben gebruikt - zorg ervoor dat u dit instelt op wat logisch is in uw omgeving. Het draait allemaal om het verzadigen van de MySQL-doelinstantie - ofwel CPU of I/O, afhankelijk van het knelpunt. We willen er zoveel mogelijk uithalen om ervoor te zorgen dat we alle beschikbare bronnen hebben gebruikt voor het laden van de gegevens.
Nadat de hoofdgegevens zijn geladen, zijn er nog twee stappen die moeten worden genomen, beide hebben betrekking op RDS-internals en beide kunnen onze replicatie verbreken. Ten eerste bevat RDS een aantal rds_*-tabellen in het mysql-schema. We willen ze laden voor het geval sommige ervan door RDS worden gebruikt - replicatie zal breken als onze slaaf ze niet heeft. We kunnen het op de volgende manier doen:
[email protected]:~/mydumper# for i in $(ls -alh /tmp/rdsdump_sys/ | grep rds | awk '{print $9}') ; do echo $i ; mysql -ppass -uroot mysql < /tmp/rdsdump_sys/$i ; done
mysql.rds_configuration-schema.sql
mysql.rds_configuration.sql
mysql.rds_global_status_history_old-schema.sql
mysql.rds_global_status_history-schema.sql
mysql.rds_heartbeat2-schema.sql
mysql.rds_heartbeat2.sql
mysql.rds_history-schema.sql
mysql.rds_history.sql
mysql.rds_replication_status-schema.sql
mysql.rds_replication_status.sql
mysql.rds_sysinfo-schema.sql
Een soortgelijk probleem is met tijdzonetabellen, we moeten ze laden met behulp van gegevens van de RDS-instantie:
[email protected]:~/mydumper# for i in $(ls -alh /tmp/rdsdump_sys/ | grep time_zone | grep -v schema | awk '{print $9}') ; do echo $i ; mysql -ppass -uroot mysql < /tmp/rdsdump_sys/$i ; done
mysql.time_zone_name.sql
mysql.time_zone.sql
mysql.time_zone_transition.sql
mysql.time_zone_transition_type.sql
Als dit allemaal klaar is, kunnen we replicatie instellen tussen RDS (master) en onze MySQL/EC2-instantie (slave).
Replicatie instellen
Mydumper schrijft bij het uitvoeren van een consistente dump een binaire logpositie. We kunnen deze gegevens vinden in een bestand met de naam metadata in de dumpdirectory. Laten we er eens naar kijken, we zullen dan de positie gebruiken om replicatie in te stellen.
[email protected]:~/mydumper# cat /tmp/rdsdump/metadata
Started dump at: 2017-02-03 16:17:29
SHOW SLAVE STATUS:
Host: 10.1.4.180
Log: mysql-bin-changelog.007079
Pos: 10537102
GTID:
Finished dump at: 2017-02-03 16:44:46
Een laatste ding dat we missen is een gebruiker die we zouden kunnen gebruiken om onze slaaf in te stellen. Laten we er een maken op de RDS-instantie:
[email protected]:~# mysql -ppassword -h rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
mysql> CREATE USER IF NOT EXISTS 'rds_rpl'@'%' IDENTIFIED BY 'rds_rpl_pass';
Query OK, 0 rows affected (0.04 sec)
mysql> GRANT REPLICATION SLAVE ON *.* TO 'rds_rpl'@'%';
Query OK, 0 rows affected (0.01 sec)
Nu is het tijd om onze MySQL/EC2-server van de RDS-instantie af te halen:
mysql> CHANGE MASTER TO MASTER_HOST='rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com', MASTER_USER='rds_rpl', MASTER_PASSWORD='rds_rpl_pass', MASTER_LOG_FILE='mysql-bin-changelog.007079', MASTER_LOG_POS=10537102;
Query OK, 0 rows affected, 2 warnings (0.03 sec)
mysql> START SLAVE;
Query OK, 0 rows affected (0.02 sec)
mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Queueing master event to the relay log
Master_Host: rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
Master_User: rds_rpl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin-changelog.007080
Read_Master_Log_Pos: 13842678
Relay_Log_File: relay-bin.000002
Relay_Log_Pos: 20448
Relay_Master_Log_File: mysql-bin-changelog.007079
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 10557220
Relay_Log_Space: 29071382
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 258726
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1237547456
Master_UUID: b5337d20-d815-11e6-abf1-120217bb3ac2
Master_Info_File: mysql.slave_master_info
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: System lock
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
1 row in set (0.01 sec)
De laatste stap is om ons verkeer over te zetten van de RDS-instantie naar MySQL/EC2, maar we moeten het eerst laten inhalen.
Als de slaaf de achterstand heeft ingehaald, moeten we een tussenstop uitvoeren. Om het te automatiseren, hebben we besloten om een kort bash-script voor te bereiden dat verbinding maakt met ProxySQL en doet wat gedaan moet worden.
# At first, we define old and new masters
OldMaster=rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com
NewMaster=172.30.4.238
(
# We remove entries from mysql_replication_hostgroup so ProxySQL logic won’t interfere
# with our script
echo "DELETE FROM mysql_replication_hostgroups;"
# Then we set current master to OFFLINE_SOFT - this will allow current transactions to
# complete while not accepting any more transactions - they will wait (by default for
# 10 seconds) for a master to become available again.
echo "UPDATE mysql_servers SET STATUS='OFFLINE_SOFT' WHERE hostname=\"$OldMaster\";"
echo "LOAD MYSQL SERVERS TO RUNTIME;"
) | mysql -u admin -padmin -h 127.0.0.1 -P6032
# Here we are going to check for connections in the pool which are still used by
# transactions which haven’t closed so far. If we see that neither hostgroup 10 nor
# hostgroup 20 has open transactions, we can perform a switchover.
CONNUSED=`mysql -h 127.0.0.1 -P6032 -uadmin -padmin -e 'SELECT IFNULL(SUM(ConnUsed),0) FROM stats_mysql_connection_pool WHERE status="OFFLINE_SOFT" AND (hostgroup=10 OR hostgroup=20)' -B -N 2> /dev/null`
TRIES=0
while [ $CONNUSED -ne 0 -a $TRIES -ne 20 ]
do
CONNUSED=`mysql -h 127.0.0.1 -P6032 -uadmin -padmin -e 'SELECT IFNULL(SUM(ConnUsed),0) FROM stats_mysql_connection_pool WHERE status="OFFLINE_SOFT" AND (hostgroup=10 OR hostgroup=20)' -B -N 2> /dev/null`
TRIES=$(($TRIES+1))
if [ $CONNUSED -ne "0" ]; then
sleep 0.05
fi
done
# Here is our switchover logic - we basically exchange hostgroups for RDS and EC2
# instance. We also configure back mysql_replication_hostgroups table.
(
echo "UPDATE mysql_servers SET STATUS='ONLINE', hostgroup_id=110 WHERE hostname=\"$OldMaster\" AND hostgroup_id=10;"
echo "UPDATE mysql_servers SET STATUS='ONLINE', hostgroup_id=120 WHERE hostname=\"$OldMaster\" AND hostgroup_id=20;"
echo "UPDATE mysql_servers SET hostgroup_id=10 WHERE hostname=\"$NewMaster\" AND hostgroup_id=110;"
echo "UPDATE mysql_servers SET hostgroup_id=20 WHERE hostname=\"$NewMaster\" AND hostgroup_id=120;"
echo "INSERT INTO mysql_replication_hostgroups VALUES (10, 20, 'hostgroups');"
echo "LOAD MYSQL SERVERS TO RUNTIME;"
) | mysql -u admin -padmin -h 127.0.0.1 -P6032
Als alles klaar is, zou u de volgende inhoud in de tabel mysql_servers moeten zien:
mysql> select * from mysql_servers;
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| hostgroup_id | hostname | port | status | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
| 20 | 172.30.4.238 | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | read server |
| 10 | 172.30.4.238 | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | read server |
| 120 | rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | |
| 110 | rds2.cvsw8xpajw2b.us-east-1.rds.amazonaws.com | 3306 | ONLINE | 1 | 0 | 100 | 10 | 0 | 0 | |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+
Aan de applicatiekant zou je niet veel van een impact moeten zien, dankzij het vermogen van ProxySQL om query's enige tijd in de wachtrij te plaatsen.
Hiermee hebben we het proces van het verplaatsen van uw database van RDS naar EC2 afgerond. De laatste stap die we moeten doen, is onze RDS-slaaf verwijderen - het heeft zijn werk gedaan en het kan worden verwijderd.
In onze volgende blogpost bouwen we daarop voort. We zullen een scenario doorlopen waarin we onze database van AWS/EC2 naar een aparte hostingprovider zullen verhuizen.