sql >> データベース >  >> RDS >> Mysql

クラウド内のMySQL-AmazonRDSから独自のサーバーへのオンライン移行:パート2

    前に見たように、企業がMySQLのRDSからデータを移動するのは難しいかもしれません。このブログの最初の部分では、EC2でターゲット環境をセットアップし、アプリケーションとRDSの間にプロキシレイヤー(ProxySQL)を挿入する方法を紹介しました。この第2部では、データを独自のサーバーに実際に移行し、ダウンタイムなしでアプリケーションを新しいデータベースインスタンスにリダイレクトする方法を示します。

    RDSからのデータのコピー

    ProxySQLを介してデータベーストラフィックを実行したら、RDSからデータをコピーする準備を開始できます。 RDSとEC2で実行されているMySQLインスタンス間のレプリケーションを設定するには、これを行う必要があります。これが完了したら、トラフィックをRDSからMySQL/EC2にリダイレクトするようにProxySQLを設定します。

    このシリーズの最初のブログ投稿で説明したように、RDSからデータを取得する唯一の方法は論理ダンプを使用することです。インスタンスにアクセスできないと、xtrabackupのようなホットな物理バックアップツールを使用できません。スナップショットから新しいRDSインスタンス以外のものを構築する方法がないため、スナップショットを使用することもできません。

    論理ダンプツールに限定されているため、論理オプションはmydumper/myloaderを使用してデータを処理することです。幸い、mydumperは一貫性のあるバックアップを作成できるため、mydumperを使用して、新しいスレーブが接続するbinlog座標を提供できます。 RDSレプリカを構築する際の主な問題は、binlogローテーションポリシーです-論理的なダンプとロードは、より大きな(数百ギガバイト)データセットでは数日かかる場合があります このプロセス全体の間、RDSインスタンスにbinlogを保持する必要があります。もちろん、RDSでbinlogローテーションの保持を増やすことはできますが(mysql.rds_set_configuration('binlogretention hours'、24);-最大7日間保持できます)、別の方法で行う方がはるかに安全です。

    ダンプの取得に進む前に、RDSインスタンスにレプリカを追加します。

    AmazonRDSダッシュボード RDSでレプリカDBを作成する

    「CreateReadReplica」ボタンをクリックすると、「マスター」RDSレプリカでスナップショットが開始されます。これは、新しいスレーブをプロビジョニングするために使用されます。このプロセスには数時間かかる場合があります。これはすべて、ボリュームサイズ、最後にスナップショットが作成されたのはいつか、ボリュームのパフォーマンス(io1 / gp2?磁気?ボリュームのpIOPSはいくつですか?)によって異なります。

    マスターRDSレプリカ

    スレーブの準備ができたら(ステータスが「使用可能」に変更されたら)、RDSエンドポイントを使用してスレーブにログインできます。

    RDSスレーブ

    ログインすると、スレーブでのレプリケーションを停止します。これにより、RDSマスターがバイナリログをパージせず、ダンプ/リロードプロセスが完了した後もEC2スレーブで引き続き利用できるようになります。

    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がタスクを完了するまで待つ必要があります。

    もう1つの手順が必要です。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ユーザーにはRDSに対する「SUPER」権限がないため、最初から再作成することをお勧めします。コピーする必要があるのは、アプリケーションユーザーへの付与です。また、ProxySQL(この場合はproxysql-monitor)で使用されるユーザーをコピーする必要があります。

    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

    4つのスレッド(-t 4)を使用していることに注意してください。これは、環境で意味のあるものに設定してください。ボトルネックに応じて、ターゲットのMySQLインスタンス(CPUまたはI / O)を飽和させることがすべてです。データの読み込みに利用可能なすべてのリソースを確実に使用できるように、可能な限り絞り込みたいと考えています。

    メインデータが読み込まれた後、さらに2つの手順を実行する必要があります。どちらも、RDS内部に関連しており、両方ともレプリケーションを中断する可能性があります。まず、RDSにはmysqlスキーマにいくつかのrds_*テーブルが含まれています。それらの一部が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は、一貫性のあるダンプを実行するときに、バイナリログの位置を書き留めます。このデータは、ダンプディレクトリのメタデータと呼ばれるファイルにあります。それを見てみましょう。次に、その位置を使用してレプリケーションを設定します。

    [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に切り替えることですが、最初に追いつくようにする必要があります。

    スレーブが追いついたら、カットオーバーを実行する必要があります。それを自動化するために、ProxySQLに接続して必要なことを実行する短いbashスクリプトを準備することにしました。

    # 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スレーブを削除することです。これはその役割を果たし、削除できます。

    次のブログ投稿では、それを基に構築します。データベースをAWS/EC2から別のホスティングプロバイダーに移動するシナリオを順を追って説明します。


    1. 更新部分で新しい値と古い値の両方を使用できるようにUPSERTを実行する方法

    2. LIMIT句に大きなオフセットを使用してMySQLクエリを高速化するにはどうすればよいですか?

    3. SQL Serverで外部キーの依存関係を見つける方法は?

    4. トップ/トップ降順中央値ソリューションの改善