2015年6月3日水曜日

PHP + MySQLのフェイルオーバー(mysqlnd_msを使う)

PHPをお使いの方、mysqlnd_msというPECL拡張モジュールをご存知でしょうか?
http://php.net/manual/ja/book.mysqlnd-ms.php

mysqlndを使って、レプリケーションやロードバランシングするモジュールです。
以前取り上げたPerconaなどのMySQLマルチマスタレプリケーションを組み合わせると、
お手軽にフェイルオーバー構成が出来ちゃいます。(もちろん自己責任で!!!!!)

CentOS7でのインストール方法は以下の通りです。
# yum -y install php_mysqlnd
# pecl install mysqlnd_ms

インストール後、モジュールの読み込みに必要な設定をphp.iniまたは設定ファイルに記述します。
CentOS7なので、「/etc/php.d/」の下に「mysqlnd_ms.ini」と名前をつけて保存します。
内容は下記の通りです。
extension=json.so
extension=mysqlnd.so
extension=mysqlnd_ms.so
mysqlnd_ms.enable = 1
mysqlnd_ms.disable_rw_split = 1
mysqlnd_ms.force_config_usage = 1
mysqlnd_ms.multi_master = 1
mysqlnd_ms.config_file = "/etc/mysqlnd_ms.json"

なお、json.soは、後ほどコマンドラインで実行するために追記しています。
今回はマルチマスタ構成なので、mysqlnd_ms.multi_master=1としています。
mysqlnd_ms.config_fileには、設定ファイル(JSON形式)の絶対パスを記述します。

設定ファイルはこのようにしました。
{
  "myapp": {
    "master": {
      "master_1": {
        "host": "10.0.0.6",
        "port": "3306"
      },
      "master_2": {
        "host": "10.0.0.7",
        "port": "3306"
      }
    },
    "slave": {},
    "filters": { "roundrobin": [] },
    "failover": { "strategy": "loop_before_master", "remember_failed": true }
  }
}

"myapp"は、mysqli関数を呼ぶ際にホスト名の代わりに入力する文字列です。後ほどPHPのサンプルを確認してください。
マルチマスタなので、masterの中にmaster_1、master_2と記述があります。
2台のサーバーへラウンドロビンで接続するので、"filters"に"roundrobin"を設定します。
ここまで設定してhttpdを再起動すると、phpinfoでmysqlnd_msの設定が反映されます。

そして、実験用PHPプログラムはこちらです。nameに$iを入れて10回ループします。
$mysqli = new mysqli("myapp", "username", "password", "testdb");

for ($i=0; $i<10 i="" p="">
  echo $mysqli->query("insert into test(name) values('".$i."');") . "\n";
}

$mysqli->close();

今回は、無停止で動作するとわかりにくいので、独立した2台のMySQLサーバーにデータを書き込んで確認してみます。

最初は2台とも動作している場合です。5件ずつ交互にデータが追加されています。
# php -c /etc/php.d/mysqlnd_ms.ini test.php
# mysql -u username -h 10.0.0.6 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 0    |
|  2 | 2    |
|  3 | 4    |
|  4 | 6    |
|  5 | 8    |
+----+------+
5 rows in set (0.00 sec)

> exit
# mysql -u username -h 10.0.0.7 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  2 | 3    |
|  3 | 5    |
|  4 | 7    |
|  5 | 9    |
+----+------+
5 rows in set (0.00 sec)

> exit


master_1を停止して実行してみましょう。master_1が停止しているので、master_2に10件追加されています。
# php -c /etc/php.d/mysqlnd_ms.ini test.php
# mysql -u username -h 10.0.0.6 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 0    |
|  2 | 2    |
|  3 | 4    |
|  4 | 6    |
|  5 | 8    |
+----+------+
5 rows in set (0.00 sec)

> exit
# mysql -u username -h 10.0.0.7 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  2 | 3    |
|  3 | 5    |
|  4 | 7    |
|  5 | 9    |
|  6 | 0    |
|  7 | 1    |
|  8 | 2    |
|  9 | 3    |
| 10 | 4    |
| 11 | 5    |
| 12 | 6    |
| 13 | 7    |
| 14 | 8    |
| 15 | 9    |
+----+------+
15 rows in set (0.00 sec)

> exit


master_2を停止して実行してみましょう。master_2が停止しているので、master_1に10件追加されています。
# php -c /etc/php.d/mysqlnd_ms.ini test.php
# mysql -u username -h 10.0.0.6 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 0    |
|  2 | 2    |
|  3 | 4    |
|  4 | 6    |
|  5 | 8    |
|  6 | 0    |
|  7 | 1    |
|  8 | 2    |
|  9 | 3    |
| 10 | 4    |
| 11 | 5    |
| 12 | 6    |
| 13 | 7    |
| 14 | 8    |
| 15 | 9    |
+----+------+
15 rows in set (0.00 sec)

> exit
# mysql -u username -h 10.0.0.7 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  2 | 3    |
|  3 | 5    |
|  4 | 7    |
|  5 | 9    |
|  6 | 0    |
|  7 | 1    |
|  8 | 2    |
|  9 | 3    |
| 10 | 4    |
| 11 | 5    |
| 12 | 6    |
| 13 | 7    |
| 14 | 8    |
| 15 | 9    |
+----+------+
15 rows in set (0.00 sec)

> exit


最後に、2台とも動かして実行してみましょう。5件ずつ追加されています。
# php -c /etc/php.d/mysqlnd_ms.ini test.php
# mysql -u username -h 10.0.0.6 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 0    |
|  2 | 2    |
|  3 | 4    |
|  4 | 6    |
|  5 | 8    |
|  6 | 0    |
|  7 | 1    |
|  8 | 2    |
|  9 | 3    |
| 10 | 4    |
| 11 | 5    |
| 12 | 6    |
| 13 | 7    |
| 14 | 8    |
| 15 | 9    |
| 16 | 0    |
| 17 | 2    |
| 18 | 4    |
| 19 | 6    |
| 20 | 8    |
+----+------+
20 rows in set (0.01 sec)

> exit
# mysql -u username -h 10.0.0.7 -p test.db
Enter password:

> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | 1    |
|  2 | 3    |
|  3 | 5    |
|  4 | 7    |
|  5 | 9    |
|  6 | 0    |
|  7 | 1    |
|  8 | 2    |
|  9 | 3    |
| 10 | 4    |
| 11 | 5    |
| 12 | 6    |
| 13 | 7    |
| 14 | 8    |
| 15 | 9    |
| 16 | 1    |
| 17 | 3    |
| 18 | 5    |
| 19 | 7    |
| 20 | 9    |
+----+------+
20 rows in set (0.00 sec)

> exit


PHPプログラムの接続時のホスト名のみ変更するだけで、プログラム自体を変更することなく導入できることがわかってもらえたかと思います。

なお、WindowsでもDLLがコンパイルできれば利用可能なようです。
http://php.net/manual/ja/install.windows.building.php

※追記 2015/06/03
こちらから各バージョン用DLLがダウンロードできます。
http://pecl.php.net/package/mysqlnd_ms/1.5.2/windows

なお、ドライバが対応しているので、mysqli関数のみならず、PDOやmysql関数からも利用できます。
http://php.net/manual/ja/mysqlnd-ms.quickstart.usage.php

お手軽にできるという点で、試してみる価値はあると思います。



0 件のコメント: