sql >> Databasteknik >  >> RDS >> Mysql

MySQL i molnet - Onlinemigrering från Amazon RDS till din egen server:Del 2

Som vi såg tidigare kan det vara en utmaning för företag att flytta sina data från RDS för MySQL. I den första delen av den här bloggen visade vi dig hur du ställer in din målmiljö på EC2 och infogar ett proxylager (ProxySQL) mellan dina applikationer och RDS. I den här andra delen kommer vi att visa dig hur du gör den faktiska migreringen av data till din egen server och sedan omdirigerar dina applikationer till den nya databasinstansen utan driftstopp.

Kopierar data från RDS

När vi väl har vår databastrafik igång genom ProxySQL kan vi börja förbereda oss för att kopiera våra data från RDS. Vi måste göra detta för att ställa in replikering mellan RDS och vår MySQL-instans som körs på EC2. När detta är gjort kommer vi att konfigurera ProxySQL för att omdirigera trafik från RDS till vår MySQL/EC2.

Som vi diskuterade i det första blogginlägget i den här serien, är det enda sättet du kan få ut data från RDS via logisk dump. Utan tillgång till instansen kan vi inte använda några heta, fysiska säkerhetskopieringsverktyg som xtrabackup. Vi kan inte heller använda ögonblicksbilder eftersom det inte finns något sätt att bygga något annat än en ny RDS-instans från ögonblicksbilden.

Vi är begränsade till logiska dumpningsverktyg, därför skulle det logiska alternativet vara att använda mydumper/myloader för att bearbeta data. Lyckligtvis kan mydumper skapa konsekventa säkerhetskopior så att vi kan lita på att den tillhandahåller binlog-koordinater för vår nya slav att ansluta till. Huvudproblemet när du bygger RDS-repliker är binlogrotationspolicy - logisk dumpning och laddning kan ta till och med dagar på större (hundratals gigabyte) datamängder och du måste ha binloggar på RDS-instansen under hela denna process. Visst, du kan öka retentionen av binlogrotation på RDS (ring mysql.rds_set_configuration('binlog retention hours', 24); - du kan behålla dem i upp till 7 dagar) men det är mycket säkrare att göra det annorlunda.

Innan vi fortsätter med att ta en dumpning kommer vi att lägga till en replika till vår RDS-instans.

Amazon RDS Dashboard Skapa replika DB i RDS

När vi klickar på knappen "Skapa läs replika" kommer en ögonblicksbild att startas på "master" RDS-repliken. Den kommer att användas för att tillhandahålla den nya slaven. Processen kan ta timmar, allt beror på volymstorleken, när togs en ögonblicksbild senast och volymens prestanda (io1/gp2? Magnetisk? Hur många pIOPS en volym har?).

Master RDS Replica

När slaven är klar (dess status har ändrats till "tillgänglig") kan vi logga in på den med dess RDS-slutpunkt.

RDS-slav

När vi väl har loggat in kommer vi att stoppa replikeringen på vår slav - detta säkerställer att RDS-mastern inte rensar binära loggar och de kommer fortfarande att vara tillgängliga för vår EC2-slav när vi har slutfört vår dumpnings-/omladdningsprocess.

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 är det äntligen dags att kopiera data till EC2. Först måste vi installera mydumper. Du kan få det från github:https://github.com/maxbube/mydumper. Installationsprocessen är ganska enkel och bra beskriven i readme-filen, så vi kommer inte att täcka det här. Troligtvis måste du installera ett par paket (anges i readme) och det svåraste är att identifiera vilket paket som innehåller mysql_config - det beror på MySQL-smaken (och ibland även MySQL-versionen).

När du har mydumper kompilerad och redo att köra kan du köra den:

[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
. 

Observera --lock-all-tables som säkerställer att ögonblicksbilden av data kommer att vara konsekvent och det kommer att vara möjligt att använda den för att skapa en slav. Nu måste vi vänta tills mydumper slutfört sin uppgift.

Ytterligare ett steg krävs - vi vill inte återställa mysql-schemat men vi måste kopiera användare och deras anslag. Vi kan använda pt-show-grants för det:

[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

Exempel på pt-show-grants kan se ut så här:

-- 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'@'%';

Det är upp till dig att välja vilka användare som krävs för att kopieras till din MySQL/EC2-instans. Det är inte vettigt att göra det för dem alla. Till exempel har root-användare inte "SUPER"-behörighet på RDS så det är bättre att återskapa dem från början. Det du behöver kopiera är bidrag till din applikationsanvändare. Vi måste också kopiera användare som används av ProxySQL (proxysql-monitor i vårt fall).

Infoga data i din MySQL/EC2-instans

Som nämnts ovan vill vi inte återställa systemscheman. Därför kommer vi att flytta filer relaterade till dessa scheman från vår mydumper-katalog:

[email protected]:~# mkdir /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/mysql* /tmp/rdsdump_sys/
[email protected]:~# mv /tmp/rdsdump/sys* /tmp/rdsdump_sys/

När vi är klara med det är det dags att börja ladda data till MySQL/EC2-instansen:

[email protected]:~/mydumper# ./myloader -d /tmp/rdsdump/ -u tpcc -p tpccpass -t 4 --overwrite-tables -h 172.30.4.238

Observera att vi använde fyra trådar (-t 4) - se till att du ställer in detta till vad som är vettigt i din miljö. Det handlar om att mätta mål-MySQL-instansen - antingen CPU eller I/O, beroende på flaskhalsen. Vi vill pressa ut så mycket som möjligt för att säkerställa att vi använde alla tillgängliga resurser för att ladda data.

Efter att huvuddatan har laddats finns det ytterligare två steg att ta, båda är relaterade till RDS-interna komponenter och båda kan bryta vår replikering. För det första innehåller RDS ett par rds_*-tabeller i mysql-schemat. Vi vill ladda dem om några av dem används av RDS - replikering kommer att gå sönder om vår slav inte kommer att ha dem. Vi kan göra det på följande sätt:

[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

Liknande problem är med tidszonstabeller, vi måste ladda dem med data från RDS-instansen:

[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

När allt detta är klart kan vi ställa in replikering mellan RDS (master) och vår MySQL/EC2-instans (slav).

Ställa in replikering

Mydumper, när den utför en konsekvent dumpning, skriver ner en binär loggposition. Vi kan hitta dessa data i en fil som heter metadata i dumpkatalogen. Låt oss ta en titt på det, vi kommer sedan att använda positionen för att ställa in replikering.

[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

En sista sak vi saknar är en användare som vi kan använda för att ställa in vår slav. Låt oss skapa en på RDS-instansen:

[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 är det dags att slava vår MySQL/EC2-server från RDS-instansen:

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)

Sista steget blir att byta trafik från RDS-instansen till MySQL/EC2, men vi måste låta den komma ikapp först.

När slaven har kommit ikapp måste vi utföra en cutover. För att automatisera det bestämde vi oss för att förbereda ett kort bash-skript som kommer att ansluta till ProxySQL och göra det som behöver göras.

# 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

När allt är klart bör du se följande innehåll i tabellen mysql_servers:

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              |             |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+

På applikationssidan bör du inte se någon större inverkan, tack vare ProxySQL:s förmåga att köa frågor under en tid.

Med detta slutförde vi processen att flytta din databas från RDS till EC2. Sista steget att göra är att ta bort vår RDS-slav - den gjorde sitt jobb och den kan raderas.

I nästa blogginlägg kommer vi att bygga vidare på det. Vi kommer att gå igenom ett scenario där vi flyttar vår databas från AWS/EC2 till en separat värdleverantör.


  1. 10 Microsoft Access-tips för att skapa utvalda frågor

  2. Hur man hittar waitevent History of the Oracle-session

  3. SQL-kommandot INSERT fungerar men data visas inte i tabellen

  4. Använder LIKE i bindParam för en MySQL PDO-fråga