ちょっと話題の記事

専用ドライバ無しでAuroraの高速フェイルオーバーに対応してみる

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

大栗です。

Auroraは通常のRDS for MySQLと比べると元々障害時の復旧が速いのですが、高速フェイルオーバーという2〜3秒でフェイルオーバーができる機能があります。ただし専用のドライバ(MariaDB Connector/Jなど)を利用することが一般的です。先日MySQL用のプロキシサーバであるProxySQLがv2にバージョンアップして、Auroraの高速フェイルオーバーに対応したのでご紹介します。

Releases · sysown/proxysql · GitHub v2.0.2

Auroraのフェイルオーバー

Auroraはシステム変数のinnodb_read_onlyの値によって、WriterReaderのロールを判断できます。そのためinnodb_read_onlyを定期的に確認してクエリをWriterにルーティングすることで高速にフェイルオーバーができます。Auroraには書き込み専用のクラスターエンドポイントがありますが、切り替えまでも時間が少し遅く、切替時にReaderへアクセスしてしまうことがあるため注意が必要です。

Aurora MySQLの高速フェイルオーバーについては、以下のエントリーを御覧ください。こちらはJDBCドライバのMariaDB Connector/Jを利用しています。

MariaDB Connector/JによるAmazon RDS for Auroraの高速フェイルオーバー

ProxySQL

ProxySQLは高性能、高可用性なプロトコルを意識するMySQL及びフォーク(MariaDBやPercona Server)のプロキシです。ライセンスはGPLv3となっています。

ProxySQLはプロトコルを解釈するためコネクションプーリングなどができます。また管理インタフェースがSQLになっていて動的な設定が可能になっているもの特徴です。

以下のように設定ファイル(CONFIG FILE)からメモリに内容を明示的に呼び出して、ランタイム適用し、ディスク(SQLite)に書き込み永続化します。管理インタフェースはMySQL互換になっており、mysqlコマンドでログインできます。SQLを実行して内容を変更することもできます。ディスク(SQLite)に書き込んだものは、次回起動時に自動的に読み込まれます。一部のパラメータ(datadirerrorlog)以外は設定ファイル(CONFIG FILE)から自動で読み込まれないため注意が必要です。

+-------------------------+
|         RUNTIME         |
+-------------------------+
       /|\          |
        |           |
    [1] |       [2] |
        |          \|/
+-------------------------+
|         MEMORY          |
+-------------------------+ _
       /|\          |      |\
        |           |        \
    [3] |       [4] |         \ [5]
        |          \|/         \
+-------------------------+  +-------------------------+
|          DISK           |  |       CONFIG FILE       |
+-------------------------+  +-------------------------+

Source: Configuring ProxySQL

やってみた

事前準備として、Auroraクラスタを起動して、DBインスタンスを2台立ち上げておきます。DBのエンドポイントは以下のものとします。

  • インスタンスエンドポイント
  • aurora-1.a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com
  • aurora-2.a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com
  • クラスターエンドポイント
  • cluster1.cluster-a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com

またAuroraにアクセスするクライアントはAmazon Linux 2とします。使用するProxySQLはv2.0.2です。

手順としては

  1. ProxySQLのインストール
  2. ProxySQLの設定
  3. フェイルオーバーの確認

ProxySQLのインストール

ProxySQLのyumリポジトリを登録します。

$ cat <<EOF | sudo tee /etc/yum.repos.d/proxysql.repo
> [proxysql_repo]
> name= ProxySQL YUM repository
> baseurl=http://repo.proxysql.com/ProxySQL/proxysql-2.0.x/centos/latest
> gpgcheck=1
> gpgkey=http://repo.proxysql.com/ProxySQL/repo_pub_key
> EOF

必要なパッケージをインストールします。

$ sudo yum install -y proxysql mariadb git

インストールされたProxySQLのファイルは以下となっています。

$ rpm -ql proxysql
/etc/init.d/proxysql
/etc/proxysql.cnf
/usr/bin/proxysql
/usr/share/proxysql/tools/proxysql_galera_checker.sh
/usr/share/proxysql/tools/proxysql_galera_writer.pl

現バージョンのrpmにはsystemd用のユニットファイルが入っていないようなので、リポジトリから持ってきます。

$ cd
$ git clone https://github.com/sysown/proxysql.git
$ sudo cp ./proxysql/systemd/system/proxysql.service /etc/systemd/system/
$ sudo systemctl daemon-reload

systemdに登録します。

$ sudo systemctl enable proxysql.service
Created symlink from /etc/systemd/system/multi-user.target.wants/proxysql.service to /etc/systemd/system/proxysql.service.

ProxySQLの設定

ProxySQLの設定ファイルを記述します。admin_variablesでは管理インタフェースのパラメータを定義します。mysql_variablesではMySQLのパラメータを定義します。

/etc/proxysql.cnf

datadir="/var/lib/proxysql"
errorlog="/var/log/proxysql/proxysql.log"

admin_variables=
{
        admin_credentials="admin:admin"
        mysql_ifaces="127.0.0.1:6032;/tmp/proxysql_admin.sock"
}

mysql_variables=
{
        threads=4
        max_connections=2048
        default_query_delay=0
        default_query_timeout=36000000
        have_compress=true
        hostgroup_manager_verbose=0
        poll_timeout=2000
        interfaces="127.0.0.1:6033;/tmp/proxysql.sock"
        default_schema="information_schema"
        stacksize=1048576
        server_version="5.7.12B"
        connect_timeout_server=3000
        max_allowed_packet=67108864
        monitor_username="awsuser"
        monitor_password="mypassword"
        monitor_history=600000
        monitor_connect_interval=60000
        monitor_ping_interval=1000
        monitor_read_only_interval=500
        monitor_read_only_timeout=500
        ping_interval_server_msec=120000
        ping_timeout_server=500
        commands_stats=true
        sessions_sort=true
        connect_retries_on_failure=10

}

ログファイルのパスerrorlog/var/log/proxysql/proxysql.logにしたのでディレクトリを作成します。(デフォルトは/var/lib/proxysql/proxysql.logです。)

$ sudo mkdir /var/log/proxysql
$ sudo chown proxysql:proxysql /var/log/proxysql

ここでProxySQLを起動します。

$ sudo systemctl start proxysql

ProxySQLの管理インタフェースにログインします。

$ mysql -uadmin -padmin -h 127.0.0.1 -P 6032
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.7.12B (ProxySQL Admin Module)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

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

MySQL [(none)]>

コンフィグファイルのmysql_usersの内容(バックエンドのAuroraのユーザー情報)をロードして、ランタイムに適用し、ディスクに永続化します。ランタイムに適用した後にランタイムからメモリに内容を保存しているのはパスワードをハッシュ化するためです。

MySQL [(none)]> INSERT INTO mysql_users (username,password,active,default_hostgroup,default_schema,transaction_persistent) values ('awsuser','mypassword',1,1,'mydb',1);
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> LOAD MYSQL USERS TO RUNTIME; SAVE MYSQL USERS FROM RUNTIME; SAVE MYSQL USERS TO DISK;
Query OK, 1 row affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Auroraの各DBインスタンスのエンドポイントを登録します。少し分かりにくいのですが、現在のWriterのエンドポイントをhostgroup_idが1と2に登録して、それ以外のインスタンスのエンドポイントをhostgroup_idが2に登録して下さい。mysql_replication_hostgroupscheck_typeinnodb_read_onlyに設定することでAuroraの高速フェイルオーバーに対応できます。

MySQL [(none)]> INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,max_connections) VALUES ('aurora-1.a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com',1,3306,1000,2000);
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,max_connections) VALUES ('aurora-1.a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com',2,3306,1000,2000);
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> INSERT INTO mysql_servers (hostname,hostgroup_id,port,weight,max_connections) VALUES ('aurora-2.a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com',2,3306,1000,2000);
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> INSERT INTO mysql_replication_hostgroups(writer_hostgroup,reader_hostgroup,comment,check_type) VALUES (1,2,'aws-aurora','innodb_read_only');
Query OK, 1 row affected (0.00 sec)

MySQL [(none)]> LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;
Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

コンフィグファイルのmysql_variablesの内容をロードして、ランタイムに適用し、ディスクに永続化します。

MySQL [(none)]> LOAD MYSQL VARIABLES FROM CONFIG; LOAD MYSQL VARIABLES TO RUNTIME; SAVE MYSQL VARIABLES TO DISK;
Query OK, 25 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 110 rows affected (0.00 sec)

コンフィグファイルのadmin_variablesの内容をロードして、ランタイムに適用し、ディスクに永続化します。

MySQL [(none)]> LOAD ADMIN VARIABLES FROM CONFIG; LOAD ADMIN VARIABLES TO RUNTIME; SAVE ADMIN VARIABLES TO DISK;
Query OK, 2 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 32 rows affected (0.00 sec)

これでProxySQLのフェイルオーバーの設定は完了です。

フェイルオーバーの確認

ここからフェイルオーバーの挙動を確認します。

確認のために以下のようなスクリプトを作成しました。

test1.sh

#! /bin/bash

while true
do
  DATETIME=$(date "+%Y-%m-%d %T.%N")
  (echo "select '${DATETIME}', now(3), @@hostname, @@innodb_read_only;" | mysql -uawsuser -pmypassword -h 127.0.0.1 -P 6033 -s) &
  sleep 0.5
done

Auroraをフェイルオーバーさせてからtest1.shを実行してみます。するとアクセスエラーが出ずに新しい接続ができるまでProxySQLが待ってアクセスさせます。

$ test1.sh
2019-03-03 22:57:42.892678638	2019-03-03 22:57:42.898	ip-10-7-1-188	0
2019-03-03 22:57:43.394422969	2019-03-03 22:57:43.400	ip-10-7-1-188	0
2019-03-03 22:57:43.896195975	2019-03-03 22:57:43.901	ip-10-7-1-188	0
2019-03-03 22:57:45.903019170	2019-03-03 22:57:46.682	ip-10-7-2-55	0
2019-03-03 22:57:44.397923446	2019-03-03 22:57:46.682	ip-10-7-2-55	0
2019-03-03 22:57:45.401376866	2019-03-03 22:57:46.712	ip-10-7-2-55	0
2019-03-03 22:57:44.899675289	2019-03-03 22:57:46.715	ip-10-7-2-55	0
2019-03-03 22:57:46.404922113	2019-03-03 22:57:46.716	ip-10-7-2-55	0
2019-03-03 22:57:46.906811093	2019-03-03 22:57:46.912	ip-10-7-2-55	0
2019-03-03 22:57:47.408530454	2019-03-03 22:57:47.414	ip-10-7-2-55	0

タイミングが悪いと接続エラーが1回発生して、他は接続に時間がかかっていますが正常にアクセスできています。

$ test1.sh
2019-03-03 16:50:40.986009984	2019-03-03 16:50:40.992	ip-10-7-1-188	0
2019-03-03 16:50:41.487770905	2019-03-03 16:50:41.493	ip-10-7-1-188	0
2019-03-03 16:50:41.989562015	2019-03-03 16:50:41.995	ip-10-7-1-188	0
2019-03-03 16:50:42.491364838	2019-03-03 16:50:42.497	ip-10-7-1-188	0
2019-03-03 16:50:42.993140431	2019-03-03 16:50:42.999	ip-10-7-1-188	0
2019-03-03 16:50:43.494924476	2019-03-03 16:50:43.500	ip-10-7-1-188	0
2019-03-03 16:50:43.996640031	2019-03-03 16:50:44.002	ip-10-7-1-188	0
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
2019-03-03 16:50:46.505309320	2019-03-03 16:50:47.200	ip-10-7-2-55	0
2019-03-03 16:50:47.007015427	2019-03-03 16:50:47.201	ip-10-7-2-55	0
2019-03-03 16:50:46.003570112	2019-03-03 16:50:47.225	ip-10-7-2-55	0
2019-03-03 16:50:45.000181268	2019-03-03 16:50:47.227	ip-10-7-2-55	0
2019-03-03 16:50:45.501884631	2019-03-03 16:50:47.229	ip-10-7-2-55	0
2019-03-03 16:50:47.508841424	2019-03-03 16:50:47.514	ip-10-7-2-55	0
2019-03-03 16:50:48.010660980	2019-03-03 16:50:48.017	ip-10-7-2-55	0
2019-03-03 16:50:48.512389025	2019-03-03 16:50:48.517	ip-10-7-2-55	0
2019-03-03 16:50:49.014104387	2019-03-03 16:50:49.020	ip-10-7-2-55	0
2019-03-03 16:50:49.515826670	2019-03-03 16:50:49.521	ip-10-7-2-55	0

同様の確認をクラスターエンドポイントに対して実行して挙動の違いを確認します。

test2.sh

#! /bin/bash

while true
do
  DATETIME=$(date "+%Y-%m-%d %T.%N")
  (echo "select '${DATETIME}', now(3), @@hostname, @@innodb_read_only;" | mysql -uawsuser -pmypassword -h cluster1.cluster-a1b2c3d4e5f6.ap-northeast-1.rds.amazonaws.com -s) &
  sleep 0.5
done

クラスターエンドポイントのフェイルオーバーの場合は、5秒程度アクセスができずエラーになります。その後に接続が可能なりますが、Writerにアクセスせず'Reader'にアクセスしている接続があります。接続断から正常にアクセスができるようになるまで10秒以上かかり、切り替え直後はReaderへ接続することがあります。コネクションプールをしている場合はWriterと認識しながらReaderへ接続してしまう恐れがあります。

$ test2.sh
2019-03-03 17:07:38.481261780	2019-03-03 17:07:38.527	ip-10-7-2-55	0
2019-03-03 17:07:38.982959640	2019-03-03 17:07:38.994	ip-10-7-2-55	0
2019-03-03 17:07:39.484645225	2019-03-03 17:07:39.498	ip-10-7-2-55	0
2019-03-03 17:07:39.986400140	2019-03-03 17:07:40.036	ip-10-7-2-55	0
2019-03-03 17:07:40.488067076	2019-03-03 17:07:40.518	ip-10-7-2-55	0
2019-03-03 17:07:40.989787855	2019-03-03 17:07:41.008	ip-10-7-2-55	0
2019-03-03 17:07:41.491802337	2019-03-03 17:07:41.508	ip-10-7-2-55	0
2019-03-03 17:07:41.993609782	2019-03-03 17:07:42.049	ip-10-7-2-55	0
2019-03-03 17:07:42.495282630	2019-03-03 17:07:42.508	ip-10-7-2-55	0
2019-03-03 17:07:42.997026431	2019-03-03 17:07:43.078	ip-10-7-2-55	0
2019-03-03 17:07:43.498786054	2019-03-03 17:07:43.522	ip-10-7-2-55	0
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
ERROR 2003 (HY000): Can't connect to MySQL server on 'cluster1.cluster-cahdiejcylf2.ap-northeast-1.rds.amazonaws.com' (111)
2019-03-03 17:07:48.014351001	2019-03-03 17:07:48.154	ip-10-7-2-55	1
2019-03-03 17:07:48.516025754	2019-03-03 17:07:48.637	ip-10-7-1-188	0
2019-03-03 17:07:49.017779788	2019-03-03 17:07:49.143	ip-10-7-1-188	0
2019-03-03 17:07:49.519452710	2019-03-03 17:07:49.572	ip-10-7-2-55	1
2019-03-03 17:07:50.021254718	2019-03-03 17:07:50.081	ip-10-7-1-188	0
2019-03-03 17:07:50.522961847	2019-03-03 17:07:50.579	ip-10-7-1-188	0
2019-03-03 17:07:51.024747160	2019-03-03 17:07:51.046	ip-10-7-2-55	1
2019-03-03 17:07:51.526463867	2019-03-03 17:07:51.592	ip-10-7-1-188	0
2019-03-03 17:07:52.028177070	2019-03-03 17:07:52.050	ip-10-7-2-55	1
2019-03-03 17:07:52.529906556	2019-03-03 17:07:52.550	ip-10-7-1-188	0
2019-03-03 17:07:53.031710290	2019-03-03 17:07:53.053	ip-10-7-1-188	0
2019-03-03 17:07:53.533451786	2019-03-03 17:07:53.595	ip-10-7-2-55	1
2019-03-03 17:07:54.035212374	2019-03-03 17:07:54.090	ip-10-7-1-188	0
2019-03-03 17:07:54.537028924	2019-03-03 17:07:54.551	ip-10-7-2-55	1
2019-03-03 17:07:55.038785867	2019-03-03 17:07:55.053	ip-10-7-1-188	0
2019-03-03 17:07:55.540528655	2019-03-03 17:07:55.624	ip-10-7-1-188	0
2019-03-03 17:07:56.042264895	2019-03-03 17:07:56.102	ip-10-7-1-188	0
2019-03-03 17:07:56.543907075	2019-03-03 17:07:56.603	ip-10-7-1-188	0
2019-03-03 17:07:57.045989555	2019-03-03 17:07:57.060	ip-10-7-1-188	0
2019-03-03 17:07:57.547804169	2019-03-03 17:07:57.598	ip-10-7-1-188	0
2019-03-03 17:07:58.049725021	2019-03-03 17:07:58.066	ip-10-7-1-188	0
2019-03-03 17:07:58.551453339	2019-03-03 17:07:58.567	ip-10-7-1-188	0
2019-03-03 17:07:59.053244992	2019-03-03 17:07:59.104	ip-10-7-1-188	0
2019-03-03 17:07:59.554931207	2019-03-03 17:07:59.571	ip-10-7-1-188	0

さいごに

今まで高速フェイルオーバーを行うにはMariaDB Connector/Jの様なドライバを使うか、HAProxy 1.6以上で外部スクリプトのチェック(fujiwaraさんが実施しています)を行うなどの方法がありました。MariaDB Connector/Jの場合はJVMに限定されるし、HAProxyの場合はAmazon Linuxのリポジトリのバージョンが1.5のため使用できずHAProxy 1.6以降の信用できるリポジトリのrpmが出回っていない状態でした(自分で野良ビルドしたくない派)。

ProxySQLがv2になり公式のrpmで動かせるようになったので簡単に試せるようになりました。Auroraを利用する場合にはProxySQLをセットで使用する事を検討しても良いかもしれません。注意点として、別途ProxySQLを別インスタンスに立てるとその障害が発生した場合の事を考えなければならないので、個人的にはAPサーバに同居させることをお勧めします。