Mysql
 sql >> база данни >  >> RDS >> Mysql

MySQL в облака - онлайн миграция от Amazon RDS към вашия собствен сървър:Част 2

Както видяхме по-рано, може да е предизвикателство за компаниите да преместят данните си от RDS за MySQL. В първата част на този блог ви показахме как да настроите вашата целева среда на EC2 и да вмъкнете прокси слой (ProxySQL) между вашите приложения и RDS. В тази втора част ще ви покажем как да извършите действителната миграция на данни към собствения си сървър и след това да пренасочите приложенията си към новата инстанция на базата данни без прекъсване.

Копиране на данни от RDS

След като трафикът на базата ни данни тече през ProxySQL, можем да започнем подготовката за копиране на нашите данни от RDS. Трябва да направим това, за да настроим репликация между RDS и нашия MySQL екземпляр, работещ на EC2. След като това стане, ще конфигурираме ProxySQL да пренасочва трафика от RDS към нашия MySQL/EC2.

Както обсъдихме в първата публикация в блога от тази серия, единственият начин да извлечете данни от RDS е чрез логически дъмп. Без достъп до инстанцията не можем да използваме горещи физически инструменти за архивиране като xtrabackup. Не можем да използваме и моментни снимки, тъй като няма начин да изградим нещо друго освен нов екземпляр на RDS от моментната снимка.

Ние сме ограничени до инструменти за логично изхвърляне, следователно логичната опция би била да използваме mydumper/myloader за обработка на данните. За щастие mydumper може да създава последователни архиви, така че да можем да разчитаме на него, за да предостави binlog координати, с които нашият нов подчинен да се свърже. Основният проблем при изграждането на RDS реплики е политиката за ротация на binlog - логическото изхвърляне и зареждане може да отнеме дори дни на по-големи (стотици гигабайта) набори от данни и трябва да поддържате binlogs на екземпляра на RDS по време на целия този процес. Разбира се, можете да увеличите задържането на ротация на binlog в RDS (обадете се на mysql.rds_set_configuration('binlog retention hours', 24); - можете да ги запазите до 7 дни), но е много по-безопасно да го направите по различен начин.

Преди да продължим с изтеглянето, ще добавим реплика към нашия RDS екземпляр.

Табло за управление на Amazon RDS Създайте реплика DB в RDS

След като щракнем върху бутона „Създаване на реплика за четене“, ще бъде стартирана моментна снимка на „главната“ RDS реплика. Ще се използва за осигуряване на новия подчинен. Процесът може да отнеме часове, всичко зависи от размера на тома, кога за последен път е била направена моментна снимка и производителността на обема (io1/gp2? Магнитно? Колко pIOPS има един том?).

Реплика на Master RDS

Когато подчиненият е готов (статусът му е променен на „наличен“), можем да влезем в него, като използваме неговата RDS крайна точка.

RDS Slave

След като влезем, ще спрем репликацията на нашия подчинен – това ще гарантира, че RDS главният няма да изчисти двоичните регистрационни файлове и те ще бъдат все още достъпни за нашия EC2 slave, след като завършим процеса на изхвърляне/презареждане.

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)

Сега най-накрая е време да копирате данните в EC2. Първо, трябва да инсталираме mydumper. Можете да го получите от github:https://github.com/maxbube/mydumper. Процесът на инсталиране е доста прост и добре описан във файла readme, така че няма да го разглеждаме тук. Най-вероятно ще трябва да инсталирате няколко пакета (изброени в readme) и по-трудната част е да определите кой пакет съдържа mysql_config – зависи от вкуса на MySQL (а понякога и версията на MySQL).

След като mydumper е компилиран и готов за работа, можете да го изпълните:

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

Моля, имайте предвид --lock-all-tables, което гарантира, че моментната снимка на данните ще бъде последователна и ще бъде възможно да се използва за създаване на подчинен. Сега трябва да изчакаме, докато mydumper завърши задачата си.

Необходима е още една стъпка - не искаме да възстановяваме схемата на mysql, но трябва да копираме потребителите и техните разрешения. Можем да използваме pt-show-grants за това:

[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

Пример за pt-show-grants може да изглежда така:

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

От вас зависи да изберете кои потребители трябва да бъдат копирани във вашия MySQL/EC2 екземпляр. Няма смисъл да го правим за всички тях. Например, root потребителите нямат привилегия „SUPER“ на RDS, така че е по-добре да ги пресъздадете от нулата. Това, което трябва да копирате, са грантове за потребителя на вашето приложение. Трябва също да копираме потребители, използвани от ProxySQL (proxysql-монитор в нашия случай).

Вмъкване на данни във вашия MySQL/EC2 екземпляр

Както беше посочено по-горе, ние не искаме да възстановяваме системни схеми. Затова ще преместим файлове, свързани с тези схеми, извън нашата директория mydumper:

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

Когато приключим с него, е време да започнем да зареждаме данни в MySQL/EC2 екземпляр:

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

Моля, обърнете внимание, че използвахме четири нишки (-t 4) - уверете се, че сте задали това, което има смисъл във вашата среда. Всичко е за насищане на целевия MySQL екземпляр - или CPU, или I/O, в зависимост от тесното място. Искаме да извлечем възможно най-много от него, за да сме сигурни, че използваме всички налични ресурси за зареждане на данните.

След като основните данни бъдат заредени, трябва да предприемете още две стъпки, и двете са свързани с вътрешните части на RDS и двете може да нарушат нашата репликация. Първо, RDS съдържа няколко rds_* таблици в схемата на mysql. Искаме да ги заредим в случай, че някои от тях се използват от RDS - репликацията ще се счупи, ако нашия подчинен няма да ги има. Можем да го направим по следния начин:

[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

Подобен проблем е и с таблиците с часовите зони, трябва да ги заредим с данни от екземпляра на RDS:

[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

Когато всичко това е готово, можем да настроим репликация между RDS (главен) и нашия MySQL/EC2 екземпляр (подчинен).

Настройване на репликация

Mydumper, когато извършва последователно изхвърляне, записва двоична позиция на журнала. Можем да намерим тези данни във файл, наречен метаданни в директорията на dump. Нека да го разгледаме, след това ще използваме позицията, за да настроим репликацията.

[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

Последното нещо, което ни липсва, е потребител, който бихме могли да използваме, за да настроим нашия подчинен. Нека създадем такъв в RDS екземпляр:

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

Сега е време да изключим нашия MySQL/EC2 сървър от RDS екземпляр:

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)

Последната стъпка ще бъде да превключим нашия трафик от RDS екземпляр към MySQL/EC2, но първо трябва да го оставим да навакса.

Когато робът е настигнал, трябва да извършим прекъсване. За да го автоматизираме, решихме да подготвим кратък bash скрипт, който ще се свърже с ProxySQL и ще направи това, което трябва да се направи.

# 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

Когато всичко е готово, трябва да видите следното съдържание в таблицата 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              |             |
+--------------+-----------------------------------------------+------+--------+--------+-------------+-----------------+---------------------+---------+----------------+-------------+

От страна на приложението не би трябвало да виждате голямо въздействие, благодарение на способността на ProxySQL да поставя заявки в опашка за известно време.

С това завършихме процеса на преместване на вашата база данни от RDS към EC2. Последната стъпка, която трябва да направите, е да премахнете нашия RDS slave – той си свърши работата и може да бъде изтрит.

В следващата ни публикация в блога ще надградим върху това. Ще преминем през сценарий, при който ще преместим нашата база данни от AWS/EC2 в отделен доставчик на хостинг.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да изчислим процента от две колони в MySQL

  2. LOAD DATA LOCAL INFILE е забранено в... PHP

  3. CURRENT_DATE/CURDATE() не работи като стойност на DATE по подразбиране

  4. Грешка във външния ключ на MySQL 1005 errno 150 първичен ключ като външен ключ

  5. Laravel:свързвайте се с бази данни динамично