まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:replication

(特にクラウド環境で)MySQL データベースを使って運用している皆さん、データのバックアップはどうしてますか?

色々な目的や用途、制限の中で使っているので正解は1つではないと思っています。中には「初めからバックアップ込みの DBaaS サービスを使っている」という人もいるでしょう。コスト的に問題なければそれがベストかもしれません。

自分の場合、ある環境では cron で一日一回 mysqldump で取り出した内容を圧縮してそのままオブジェクトストレージに丸投げ、という方法を採用していたりします。オブジェクトストレージにダンプデータが残っていれば、そこからリストアできる、という考え方です。ケースバイケースではあるし、クラウド業者のオプションとかにも依存はしますが、オブジェクトストレージは手軽に使えて、比較的安価な割にデータポータビリティの高いデータストレージなので、コスパ的にもあっていました。これだけだとダンプにないデータやダンプ後に変更があったデータは救えませんが、そこまでシビアなデータ管理を要求されることもないデータベースであれば、手軽なこの方法はオススメでもあります。

一方、データが失われてからリストアするのにあまり長い時間かかることが許されないような場合や、救えないデータがあってはまずい場合はこの方法は向きません。データベースサーバーを多重化するなどして「最悪、1台死んでもいい」環境を構築することになります。


最近、自分の管理している環境下で MySQL データベース(正確には MariaDB だったけど)の Master-Slave レプリケーション環境を構築する機会がありました。その時の作業を記録しておきます。

まず前提条件として、以下のような環境を想定します:
- MySQL 5.x サーバーが1台稼働中。レプリケーション設定はしていない。
- MySQL サーバーを新たにもう1台追加して、Master-Slave の2台構成にする。
- 現在使っているサーバーを Master、新たに追加するサーバーを Slave とする。
- レプリケーションの対象とするデータベースの名前は mydb とする。

以下、順に説明します。現在稼働中の MySQL サーバーを「A」と呼ぶことにします。このサーバーが Master サーバーになります。また、新たに追加する MySQL サーバーを「B」と呼ぶことにして、このサーバーを Slave サーバーとして運用します:


1. Slave 用 MySQL サーバー環境の構築(B)

Slave サーバーとなる新しい MySQL サーバー環境を構築します。この辺りを参照してください:
CentOS に MySQL をインストール/セットアップする

Slave 側にも MySQL 環境が構築できたら、mysql コマンドでレプリケーションを行う先のデータベースを作成しておきます。UTF-8 指定などは環境に合わせて適当に:
mysql > create database mydb character set utf8;

2. レプリケーション用ユーザーの作成(A)

MySQL コマンドを使って Slave が Master のバイナリログを参照する際に接続するユーザーを作成します。
この例ではユーザー名 repl、パスワード password で、192.168.1.XXX/24 環境からの接続のみ許可されたユーザーとしています:
mysql > GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.0/255.255.255.0' IDENTIFIED BY 'password';

3. Master 用の設定(A)

具体的には Master のバイナリロギングを有効にし、かつサーバーを識別するための ID を /etc/my.cnf 内に追加設定します(MariaDB の場合は /etc/my.cnf.d/server.cnf):
# vi /etc/my.cnf

[mysqld]
log-bin=mysql-bin
server-id=1001
ここまで設定したら MySQL サーバー(A)を再起動します。


4. レプリケーション用ユーザーの作成(B)

MySQL コマンドを使って Slave 内にデータを複製するユーザーを作成します。この例ではユーザー名 repl、パスワード password としています:
mysql > GRANT ALL PRIVILEGES ON *.* TO 'repl'@localhost IDENTIFIED BY 'password';

5. Slave 用の設定(B)

サーバーを識別するための ID を /etc/my.cnf 内に追加設定します(MariaDB の場合は /etc/my.cnf.d/server.cnf)。この ID はシステム全体でユニークにする必要があるため、3. で設定した内容とは異なるものにします:
# vi /etc/my.cnf

[mysqld]
log-bin=mysql-bin
server-id=1002
ここまで設定したら MySQL サーバー(B)を再起動します。


6. バイナリログ位置の確認(A)

Master 側サーバーの MySQL コマンドで以下を実行して、その結果をメモしておきます:
mysql > FLUSH TABLES WITH READ LOCK;

mysql > SHOW MASTER STATUS;

+----------------------+-----------+--------------+------------------+
| File                 | Position  | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------------+-----------+--------------+------------------+
| mysql-bin.000031     |       285 |              |                  |
+----------------------+-----------+--------------+------------------+
この結果の File がバイナリログ名、Position が現在位置です。これらの値は後に使います。

なお、"SHOW MASTER STATUS;" の実行結果が "Empty Set" と表示される場合は、File は ""(空文字)、Position は 4 とみなすことができるので、これらの値を後に使うことになります。

7. スナップショットの作成(A)

続いてこの状態のデータベースのスナップショットを取得します。6. で "FLUSH TABLES WITH READ LOCK" を実行しているのでデータベースにはロックがかかっています。この状態で別のコンソールやターミナルを使って以下のコマンドを実行します:
# mysqldump -u root -p mydb --lock-all-tables > mydbdump.db
これで指定した mydb データベースのダンプを mydbdump.db というファイルに取得することができます。取得後は再度もう一つのターミナルに戻って以下のコマンドを実行し、ロックを解除します:
mysql > UNLOCK TABLES;

8. スナップショットのコピー(AまたはB)

7. で取得したスナップショットファイルを(mydbdump.db)、Slave サーバーとなる B に転送します。SFTP などを使って A から B へ送ってもいいし、B から A に取りに行ってもいいし、全く別の方法でも構いません。スナップショットファイルが B のディスク内にあって、9 のコマンドが実行できさえすればいい、ということです。


9. スナップショットの展開(B)

7. で取得した Master のスナップショットを Slave である B の mydb データベースに展開します:
# mysql -u repl -p mydb < mydbdump.db

10. Master 情報登録(B)

続いて MySQL コマンドで Slave に Master の情報を登録します:
mysql > CHANGE MASTER TO
  MASTER_HOST='192.168.1.XXX',
  MASTER_USER='repl',
  MASTER_PASSWORD='password',
  MASTER_LOG_FILE='mysql-bin.000031',
  MASTER_LOG_POS=285;
なお、ここで指定する値ですが、MASTER_HOST は A のサーバー名(IPアドレス)、MASTER_USER は複製用(Aの)ユーザー、MASTER_PASS はそのパスワード、MASTER_LOG_FILE は 6. で取得した File の値、MASTER_LOG_POS は同 Position の値です。


11. レプリケーションスタート(B)

最後にレプリケーションを開始します:
mysql > START SLAVE;
これでレプリケーションがスタートする、はず。


スレーブを増やして、3台目以降の MySQL サーバーを構築する場合も同様にして行います。


環境によっては「初めから MySQL をクラスター環境で構築する」という選択肢もあります。そういう場合はこちらを参照してください:
CentOS に MySQL クラスター環境を構築する


(注 この記事の内容は古くなっています。新しい情報はこちらを参照してください)


Bluemix を、特に IoT 関連サービスの開発で Bluemix を使っていると、データを Cloudant に格納するのが便利です。Node-RED スターターボイラープレートに照準装備されていることもあるし、データ形式が機器ごとに異なるセンサーのデータをデータベースに格納しようとすると、テーブル定義の不要な NoSQL データベースの方が楽です。

でも NoSQL に格納されたデータは再利用が難しいです。SQL も使えないのでクエリーでデータを選別することも難しく、データを貯めるまではいいのですが、その後の利用時に手間取りがちになってしまいます。。。

そんな問題を解決する目的で IBM dashDB が提供されています。これは DB2 BLU Acceleration 技術を使った統計用 DB2 の DBaaS です。特筆する機能の1つに Claudant からの単方向レプリケーション機能が装備されていて、Claudant の特定のデータベースに格納された内容を dashDB のテーブルにレプリケーションできる、というものです。レプリケーション後は dashDB のデータとして利用できるので、普通に SQL のクエリーを使うこともできますし、カラムナストアを使った高速な統計機能を使うこともできますし、R 言語を使って解析することもできます。

データが dashDB に格納されてしまえば、こっちのもの、という感じ。 なので大量のデータを Cloudant に格納するだけして、解析が必要なデータは dashDB にレプリケーションする、という使い方がビッグデータ時代ではとてもリーズナブルなわけです。


運良く(?)Cloudant も dashDB も IBM Bluemix のサービスとして提供されています。この単方向レプリケーション機能を実際に試してみました。その時の様子を紹介します。

まず Bluemix 上の Node-RED エディタを使って IoT フローアプリケーションを作ります。このあたりの手順はこちらも参照ください。とりあえずシミュレータを使うなどして機器デバイスから発信される大量のセンサーデータを Cloudant に格納します:
2015051601


この Cloudant に格納されたデータを Bluemix 上から確認してみます。NoSQL なので、データベース内のデータ一覧を見ると中身が少しわかりにくいかもしれません。
2015051602


1つのデータを選択して詳細を見ると、より理解しやすい形で確認できます。この例では time や objectTemp, ambientTemp, accelX, ... などのセンサーデータが JSON 形式で格納されていることが確認できます:
2015051603


ではこのサービスにレプリケーション先となる dashDB サービスを追加します。アプリケーションの画面から「サービスまたは API の追加」をクリックします:
2015051604


ビッグデータカテゴリの中にある dashDB を選択してプロジェクトに追加します:
2015051605


念のため。dashDB は無料枠のある有償サービスなので、そのサービス価格を確認しておきます。デフォルトの Entry プランの場合は 1GB データまでは無料。20GB までは月5250円で使うことができます(最初の30日間はデータ量に関わらず無料)。ちなみにこのサービスで使っているソフトは、ライセンス契約で買うとものすごく高いです(苦笑)。ある意味でこれをクラウドから従量課金で使えるのはお得です。特に無料枠で使うつもりの方はデータ量に気をつけてください:
2015051606


プロジェクトに追加後の画面です。dashDB サービスが追加されたことを確認します:
2015051607


ではこの追加した dashDB に対して、Cloudant のデータを単方向でレプリケーションする設定を行います。まず Claudant 側の接続情報が必要なので、Cloudant サービスの「資格情報の表示」部分をクリックします:
2015051608


以下の様な情報が表示されます。host と username, password, そして Cloudant 内で使っていて、dashDB にレプリケーションしたいデータベースの名前をメモしておきます:
{
  "cloudantNoSQLDB": [
    {
      "name": "dotnsf-nodered-cloudantNoSQLDB",
      "label": "cloudantNoSQLDB",
      "plan": "Shared",
      "credentials": {
        "username": "(ユーザー名)",
        "password": "(パスワード)",
        "host": "(ホスト名)",
        "port": 443,
        "url": "...."
      }
    }
  ]
}

これらの情報が確認できたら dashDB への単方向レプリケーションを設定します。ダッシュボードから dashDB アイコンをクリックします:
2015051609


dashDB の説明画面が表示されるので、"LAUNCH" ボタンをクリックします:
2015051610


初期画面が表示されます。レプリケーションは初期データのロードとして設定するので "Load your data" ボタンをクリックします:
2015051611


次の画面で "Cloudant" を選択し、"load" ボタンをクリックして Cloudant からの単方向レプリケーションで初期データをロードすることを指定します:
2015051612


次の画面で Cloudant の情報と、レプリケーション先となる dashDB のデータベース名を指定します。Cloudant の情報として必要なのは以下の3点です:
 データベースURL : https://(接続情報の host の値)/(目的のデータが格納されているデータベース名)
 ユーザー名: (接続情報の username の値)
 パスワード: (接続情報の password の値)

また dashDB のデータベース名として指定するデータベースはこの段階で存在している必要はありません。存在していない場合は新規に作成します。最後に "Start Sync" ボタンをクリックして同期を実行します:
2015051613


同期の設定が正しければ、この同期が "Running" ステータスで有効に設定されたことが表示で確認できます:
2015051614


改めて "Tables" タブを選択し、テーブルにレプリケーション先に指定したテーブルを選択すると、Cloudant のデータが dashDB のテーブルとして自動的にマッピングが定義されていることが確認できます:
2015051615


ここで "Browse Data" をクリックすると、実際のデータレコードが確認できます。元々は Cloudant に含まれていたデータレコードが dashDB に格納されています。また、これはデータのコピーではなく単方向レプリケーションなので、今後 Cloudant にデータが追加されると自動的にこの dashDB のこのテーブルにデータが複製されてくることになります:
2015051616


これで IoT のセンターデータが SQL の使える dashDB に同期で格納できることが確認できました。センサーデータは書き換えることはあまり考えにくく、統計目的で参照することが多いと思われるので、単方向レプリケーションでもあまり問題にならないと思っています。これでセンサーからのビッグデータを統計目的で使う、というためのシステム基盤が簡単に作れることが分かりました。

 

このページのトップヘ