MySQLサーバのデータをAuroraにレプリケーションする stunnel編


俺です。こんばんわ
ふつうのMySQLサーバをAuroraにするため
レプリケーションでのデータ移行を検討してみます。

参照ドキュメント: Amazon Aurora とのレプリケーション

構成図

異なるVPCかつPrivate SubnetにいるMySQLとAuroraをReplicationするため、
Public Subnetに配備しているEC2同士でStunnelを張ってレプリケーションします。

今回はAWStoAWSで実践していますが、オンプレミスtoAWSでもVPStoAWSでも実装可能です。

  • Stunnel Server(Source MySQL)の存在するVPCで稼働するEC2
  • Stunnel Client(Destination Aurora)の存在するVPCで稼働するEC2

全般設定

ざっくりとこんな感じで。stunnelは別途記載
ソースデータベースはInnoDBエンジンのみで稼働しているかつ gtid-mode = OFF を前提としています。

  • MyISAMが存在する場合レプリケーションエラーになるので、ソースデータベースのMyISAMエンジンをInnoDBに変換しなければなりません。
  • AuroraはGTIDモードのレプリケーションができません
設定項目 設定内容 移行元環境 移行後環境
AWS stunnelサーバのSG 移行後VPCのstunnelで稼働するstunnelサーバのEIPとstunnel acceptポート(13306) 特に無し
DB バージョン mysql5.6.27 Aurora 5.6.10a
DB GTID OFF OFF
DB ストレージエンジン InnoDBのみ InnoDBのみ

stunnelサーバの構築

stunnelサーバ

  • インストール
$ sudo yum install -y stunnel
  • 証明書とサーバ秘密鍵の作成

省略

  • /etc/stunnel/stunnel.conf
cert = /etc/stunnel/server.crt
key = /etc/stunnel/server.key
sslVersion = TLSv1
setuid = nobody
setgid = nobody
pid = /var/run/stunnel/stunnel.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
debug = 1
output = /var/log/stunnel.log
client = no
[mysql]
accept = 13306
connect = <MySQLサーバの内部IP>:3306
  • stunnel起動
$ sudo stunnel /etc/stunnel/stunnel.conf

stunnelクライアント

  • インストール
$ sudo yum install -y stunnel
  • 証明書とサーバ秘密鍵の作成

省略

  • /etc/stunnel/stunnel.conf
cert = /etc/stunnel/server.crt
key = /etc/stunnel/server.key
sslVersion = TLSv1
setuid = nobody
setgid = nobody
pid = /var/run/stunnel/stunnel.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
debug = 1
output = /var/log/stunnel.log
client = yes
[mysql]
accept = 13306
connect = <StunnelサーバのグローバルIP>:13306
  • stunnel起動
$ sudo stunnel /etc/stunnel/stunnel.conf

接続確認

  • stunnelクライアントで実行
$ mysql -u <username>  -p<userpassword> -P 13306 -h 127.0.0.1
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 347
Server version: 5.6.27-log MySQL Community Server (GPL)

Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

これでAuroraが移行元MySQLにReplicationできるようになりました。

Auroraでレプリケーションプロシージャの実行

Auroraに接続可能なクライアントで実行します。
stunnelクライアントにmysqlコマンドをインストールしているので、やってみましょう。

ちなみにこの作業の前に、移行元MySQLからdumpしたデータを入れ込んでおいて、ポジションメモしておけば
差分レプリケーションが実現できますね。
InnoDBだけなら最高。

mysql -u <username> -p<userpassword> -h aurora.cluster-saikou.ap-northeast-1.rds.amazonaws.com
mysql> CALL mysql.rds_set_external_master ('<stunnelクライアントの内部IP>', 13306,'<MySQLサーバのレプリケーションユーザ名', '<MySQLサーバのレプリケーションユーザパスワード>', '<バイナリログファイル名>', <ポジション>, 0);
mysql> CALL mysql.rds_start_replication;

レプリケーション確認

以下のようにio_threadとsql_threadが起動していればOKです。やったぜ。

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: <stunnelクライアントの内部IP>
                  Master_User: repl
                  Master_Port: 13306
                Connect_Retry: 60
              Master_Log_File: mysqld-bin.000032
          Read_Master_Log_Pos: 15257039
               Relay_Log_File: relaylog.000154
                Relay_Log_Pos: 236
        Relay_Master_Log_File: mysqld-bin.000032
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table: mysql.rds_history,mysql.rds_replication_status,mysql.rds_sysinfo
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 15257039
              Relay_Log_Space: 850
              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: 0
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: 2580
                  Master_UUID: 0c0e2cff-ecd9-11e5-95f8-0a28d442afe1
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           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
1 row in set (0.00 sec)

レプリケーションを試してみる

sysbenchクライアントを使ってダミーデータを生成します。
移行元MySQLサーバに1億件ほどつっこんでみましょう。

データの生成

  • 移行元MySQLサーバで実行

今回のテストで使ったstunnelサーバとMySQLサーバはt2.largeで稼働しています。
データの作成完了まで約16分30秒かかりました。(timeコマンドのresultデータ取り逃がした)

$ mysql -u root -p -e "create database sbtest"
$ sysbench \
--test=oltp \
--db-driver=mysql \
--oltp-table-size=100000000 \
--mysql-password=sbtest \
prepare

レプリケーション確認

  • stunnelクライアントで実行

データ生成後に show slave status を実行すると、Seconds_Behind_Master は約2000秒の差があります。

VPC越え+stunnelなのでこの遅延はしかたないものです。

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: <stunnelクライアントの内部IP>
                  Master_User: repl
                  Master_Port: 13306
                Connect_Retry: 60
              Master_Log_File: mysqld-bin.000032
          Read_Master_Log_Pos: 15256755
               Relay_Log_File: relaylog.000116
                Relay_Log_Pos: 21359384
        Relay_Master_Log_File: mysqld-bin.000029
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table: mysql.rds_history,mysql.rds_replication_status,mysql.rds_sysinfo
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 21359220
              Relay_Log_Space: 645048921
              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: 1998★
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: 2580
                  Master_UUID: 0c0e2cff-ecd9-11e5-95f8-0a28d442afe1
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: update
           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
1 row in set (0.01 sec)

レプリケーション遅延は待てば良いので、実用性はあると考えています。
VPNを張らない(張れない)環境だったり、VPCピアリングできない環境(ソースDBがAWSではない場合)や
AuroraをPublic Accessible = true せずに実現できるので便利ではないでしょうか。
(そういえばDatabase Migration Serviceもありますね..)

ただーし、エラー無しでレプリケーションを完了させるには移行元MySQLが InnoDB のみで稼働していることが超大前提です。

おわり。

付録: MyISAM -> InnoDBレプリケーションを試してみる

移行元MySQLサーバにMyISAMが存在する場合、どのようにレプリケーションするか試してみました。

  • 移行元MySQLサーバでMyISAMテーブルを作成する
hoge@localhost [sbtest] > create table myisam_to_innodb (a int) engine='MyISAM';
Query OK, 0 rows affected (0.01 sec)```
  • 移行先Auroraのレプリケーション状態確認

AuroraでMyISAMエンジンはサポートされていないためレプリケーションエラーが発生してしまいました。

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: <stunnelクライアントの内部IP>
                  Master_User: repl
                  Master_Port: 13306
                Connect_Retry: 60
              Master_Log_File: mysqld-bin.000003
          Read_Master_Log_Pos: 611000
               Relay_Log_File: relaylog.000002
                Relay_Log_Pos: 611042
        Relay_Master_Log_File: mysqld-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table: mysql.rds_history,mysql.rds_replication_status,mysql.rds_sysinfo
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 1289
                   Last_Error: Error 'The 'MyISAM' feature is disabled; you need MySQL built with 'MyISAM' to have it working' on query. Default d
atabase: 'sbtest'. Query: 'create table myisam_to_innodb (a int) engine='MyISAM''
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 610878
              Relay_Log_Space: 612320
  • 移行先AuroraにInnoDBとしてテーブルの作成

移行元MySQLサーバに存在するMyISAMエンジンで稼働するテーブルを、
InnoDBとして作成します。

mysql > create table myisam_to_innodb (a int);
  • 移行先Auroraで発生しているレプリケーションエラーをスキップ

レプリケーションエラーをスキップします。

mysql>  CALL mysql.rds_skip_repl_error;
  • 移行元MySQLサーバに存在するMyISAMエンジンのテーブルにデータ挿入
root@localhost [sbtest] > INSERT INTO myisam_to_innodb values (1);
Query OK, 1 row affected (0.01 sec)
  • 移行先Auroraでデータ反映状態確認

やったぜ

mysql> SELECT * FROM myisam_to_innodb;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

ということで先にInnoDB化したテーブルを定義して、レプリケーションするという手段が通用しそうです。
(int型しか試していないので、実際に問題なくうまくいくかは移行テストで確認しましょう)

おわり