はじめに
みなさんMySQLを使うとき、冗長化はどうしてますか?
Master-Slaveのレプリケーションを頑張って組むか、RDSみたいなフルマネージドサービスを使うか、選択肢は色々あります。
この記事ではシンプルな構成で簡単にMySQL互換の冗長化クラスタを構築する方法を紹介します。
Master-Slaveのように複雑でなく明瞭簡潔なので、構築・運用も楽になります。
コストや自由度の面からRDSはちょっと、という人にもいいかもしれません。
細かくいうと、全ノード書き込み可能なマルチマスタで、同期的にレプリケーションを行うRDBクラスタを構築します。
もちろんトランザクションも処理できますし、障害時にフェイルオーバが発生せずダウンタイムが少ないという特徴もあります。
Percona XtraDB ClusterというオープンソースのRDBMSを使用して構築します。
MySQLフォーク
細かいことは省きますがMySQLの開発元がなんだかんだでOracleになってから、MySQLフォークの開発が盛んになっています。
また、多くのLinuxディストリビューションが標準データベースにMySQLではなくMySQLフォークを選択するようになりました。
MySQLフォークとは、ソースコードが公開されているMySQLから派生したRDBMSです。
特に有名なのは、InnoDBの代替ストレージエンジンのXtraDBを使用しているMariaDBとPercona Serverの2つです。
MariaDBはRed Hat Enterprise Linux 7の標準DBとして採用されたことでも注目されています。
PerconaもMariaDBも、簡単にいうと性能強化されたMySQL互換のRDBMSです。
そのため、MySQLからこれらのDBに乗り換えるだけで性能をあげることも可能です。
MariaDBは独自進化に向かっているのに対して、PerconaはOracleのMySQL Enterpriseに完全互換で強化を施した製品を目指しています。
(MariaDBはそのうちまたMySQL互換に寄せていくといってるらしいですが)
Percona製品はPercona社が開発しています。
Percona社はPercona Server以外にもXtraDB、XtraDB Cluster、XtraBackup、Toolkitなど周辺ツールも開発しています。
MariaDBに比べてPercona Serverは日本ではマイナーですが、XtraBackupやToolkitは使っているという方も多いんじゃないでしょうか。
次の理由から私はPerconaの方が好きなので、この記事でもPerconaで冗長化クラスタを組む方法を紹介したいと思います。
- 強いMySQL互換を目指している
- データベースエンジンや周辺ツールも同社で開発している
- 実際使ってみてPercona Serverの方が完成度が高く感じる
- 名前がかっこいい(XtraDB!!)
Percona XtraDB Cluster
Percona Server
MySQLフォークのところでも説明しましたが、Percona ServerはMySQLを元にPercona社が開発しているRDBMSです。
InnoDBの代わりにXtraDBというストレージエンジンを使用していて、
- 性能
- スケーラビリティ
- 信頼性
- 機能
- 管理
などが強化されています。
ベンチマークを見るととてもわかりやすいです。
(Percona社が出してるものですが、、)
Percona社は、元々MySQLのコンサルで実績のある会社です。
技術者が世界各地に点在していて、世界中で活動しています。
Percona XtraDB Cluster
Percona XtraDB Clusterは、Percona Serverを元に冗長化クラスタを構築するためのパッケージです。
次のコンポーネントが同梱されています。
- Percona Server
- Galera Library
- wsrep API
- Percona XtraBackup
Galera LibraryはCordership Oy社が開発しているマルチマスタ同期レプリケーションを実現するためのライブラリです。
Galera Libraryを使うことで、簡単に冗長化を行うことができます。
wsrep API(Write Set Replication API)はマルチマスタ同期レプリケーションのための標準APIです。
レプリケーションプロバイダとアプリケーション間のAPIを定義しています。
マルチマスタ同期レプリケーション
Percona XtraDB Clusterではアクティブ-アクティブなマルチマスタ同期レプリケーションを実現できます。
つまり、クラスタを構成する全ノードがマスタであり、全ノードで書き込み/読み込みが可能で、全ノード間で同期的にレプリケーションが行われます。
ここが一般的なMySQLの冗長化とは異なる部分です。
MariaDB、MySQLでもGaleraを使用したマルチマスタ同期レプリケーションクラスタが構築可能です。
全ノードがアクティブであるため、障害時にFailoverが発生することもなくダウンタイムがありません。
また、動的にノードの追加・削除が可能なため、無停止での設定変更やバージョンアップを行うことができます。
そしてこれらの操作も非常にシンプルです。
CAP定理でいうと、GaleraはCA、つまり一貫性と可用性を実現しています。
トランザクション処理のためのACID特性も保証されています。
Split Brainも発生しないように設計されており、信頼性の高いシステムが構築できます。
作るもの
前置きが長かったですが、ここから実際に構築していきます。
今回はVagrantで複数のVMを立ち上げ、クラスタを構築します。
そして最後にRailsのアプリケーションからクラスタにアクセスします。
構成
構成は次の図のようになります。
VagrantでVM(CentOS 7)を3台立ち上げ、各VMにPercona XtraDB Cluster(PXC)をインストールします。
その3台でクラスタを構築します。
(3台というのはPerconaが推奨しているクラスタの最小構成数です)
Railsアプリ用にも1台VMを立ち上げ、RailsアプリからはHAProxyを経由してDBにアクセスするようにします。
バージョン
今回使用したソフトウェアのバージョンは次の通りです。
- Vagrant 1.7.1
- VirtualBox 4.3.18
- CentOS 7.0
- Percona XtraDB Cluster 5.6.21
- Percona XtraBackup 2.2.7
- Galera 3.8
Percona XtraDB Cluster構築
まずは、PXCを構築します。
1. VagrantでCentOS起動
PXC入りCentOS 7を3台立ち上げるVagrantfileをGistに用意したので、そちらを使ってください。
https://gist.github.com/nownabe/27ffdd8fed6a3f1707e8
$ mkdir pxc_demo
$ cd pxc_demo
$ curl -O https://gist.githubusercontent.com/nownabe/27ffdd8fed6a3f1707e8/raw/62df5d42e00c483f8cbaa3818e7e5eb092836f85/Vagrantfile
$ vagrant up
少し時間がかかります。
(おまけ) Percona XtraDB Clusterのインストール
今回はVagrantfileのprovisionで自動でインストールしましたが、手動でインストールするときは次の手順になります。
(と言ってもVagrantfileに書いてある内容そのままですが)
$ sudo yum install -y epel-release
$ sudo yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
$ sudo yum install -y Percona-XtraDB-Cluster-56
epelは、PXCと依存関係のあるsocatインストールで必要になります。
2. my.cnf
次に、PXC用の/etc/my.cnf
を説明します。
上記のVagrantfileを使用した場合は、すでに設定されているのでここは眺めるだけでOKです。
wsrep_node_address
のみ各ノードごとに異なります。
[mysqld]
datadir=/var/lib/mysql
user=mysql
# Galera Libraryのパス
wsrep_provider=/usr/lib64/libgalera_smm.so
# クラスタを構成するノードのアドレス
wsrep_cluster_address=gcomm://10.6.3.101,10.6.3.102,10.6.3.103
# Galeraを使うときはROWにする必要があります
binlog_format=ROW
# Galeraが正式にサポートしているのはInnoDBだけです(Perconaは内部的にはXtraDBを使っています)
default_storage_engine=InnoDB
# これもGaleraの要件です
innodb_autoinc_lock_mode=2
# ノードのアドレス
wsrep_node_address=10.6.3.101
# SSTにxtrabackupを使用します。SSTはPXCにおけるノード間データ転送のひとつで、rsync、mysqldumpも使えます。
wsrep_sst_method=xtrabackup-v2
# クラスタ名
wsrep_cluster_name=pxcdemo
# SSTの認証情報
wsrep_sst_auth="sstuser:s3cret"
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
3. クラスタ起動
3.1 クラスタ初回起動について
今回クラスタの起動で2つの特殊な操作を行います。
- 1台目の起動
- SST用ユーザの作成
これらはクラスタの初回起動時に必要な操作になります。
まず、1台目の起動について説明します。
PXCでは普通にサービスを起動すると、/etc/my.cnf
のwsrep_cluster_address
を見て、それらのいずれかのノードに接続しに行きます。
しかし、クラスタに1台もノードがいない状態だと接続に失敗し、起動自体にも失敗します。
そのため1台目だけは特別なコマンドで起動を行う必要があります。
次はSST用ユーザの作成について説明します。
2台目以降のPXCは起動するとwsrep_cluster_address
をみてクラスタに接続します。
そして、SST(Snapshot State Transfer)によりクラスタのいずれかのノードからデータを同期します。
同期が完了するとクラスタのメンバーとして稼働し始めます。
今回の設定だとSSTに認証が必要なため、 接続される側でSST用のユーザを作っておく必要があります。
2台目以降にはユーザ情報も自動で同期されるので、1台目で1度作ればOKです。
3.2 1台目起動
では1台目を起動します。
$ vagrant ssh pxcnode-01 -c 'sudo systemctl start mysql@bootstrap'
1台目はsystemctl start mysql@bootstrap
というコマンドで起動します。
CentOS 6の場合は、service mysql bootstrap-pxc
になります。
SST用のユーザを作成します。
$ vagrant ssh pxcnode-01 -c 'mysql -uroot'
mysql> create user 'sstuser'@'localhost' identified by 's3cret';
mysql> grant RELOAD, LOCK TABLES, REPLICATION CLIENT on *.* to 'sstuser'@'localhost';
mysql> flush privileges;
mysql> exit
3.3 2台目、3台目起動
2台目と3台目は普通に起動します。
$ vagrant ssh pxcnode-02 -c 'sudo systemctl start mysql'
$ vagrant ssh pxcnode-03 -c 'sudo systemctl start mysql'
起動すると、自動でpxcnode-01からSSTによるデータ同期が始まります。
今回はほとんどデータがない状態なのですぐ終わります。
4. 動作確認
3つのノードで書き込みと確認を行っていきます。
まず、#1でデータベースを作成します。
$ vagrant ssh pxcnode-01 -c 'mysql -uroot -e "create database demo"'
#2で作成されたデータベースを確認し、テーブルを作成します。
$ vagrant ssh pxcnode-02 -c 'mysql -uroot -e "show databases"'
+--------------------+
| Database |
+--------------------+
| information_schema |
| demo |
| mysql |
| performance_schema |
| test |
+--------------------+
$ vagrant ssh pxcnode-02 -c 'mysql -uroot demo -e "create table demotable (name varchar(64))"'
#3でテーブルを確認し、挿入します。
$ vagrant ssh pxcnode-03 -c 'mysql -uroot demo -e "show tables"'
+----------------+
| Tables_in_demo |
+----------------+
| demotable |
+----------------+
$ vagrant ssh pxcnode-03 -c 'mysql -uroot demo -e "insert into demotable values (\"from #03\")"'
#1で挿入したデータを確認します。
また、Rais用のユーザとHAProxyのヘルスチェック用のユーザも作成しておきます。
$ vagrant ssh pxcnode-01 -c 'mysql -uroot demo -e "select * from demotable"'
+----------+
| name |
+----------+
| from #03 |
+----------+
$ vagrant ssh pxcnode-01 -c "mysql -uroot -e \"grant all privileges on *.* to 'demo'@'%'\""
$ vagrant ssh pxcnode-01 -c "mysql -uroot -e \"grant usage on *.* to 'haproxy'@'%'\""
こんな感じで、Percona XtraDB Clusterを使うと手軽に冗長構成RDBを構築することができます。
アプリケーションからアクセス
1. VagrantでCentOS起動
HAProxy + Rails用のVMを立ち上げます。
Rubyをビルドするので、少し時間がかかります。
$ mkdir pxc_demo_rails
$ cd pxc_demo_rails
$ curl -o Vagrantfile https://gist.githubusercontent.com/nownabe/27ffdd8fed6a3f1707e8/raw/5f66c1301a7f093ec7d99caff40584ed8a4a03ea/Vagrantfile-ruby
$ vagrant up
2. HAProxy設定
HAProxyの設定ファイルを編集して、サービスを起動します。
これもGistにあるので、ダウンロードして使ってください。
$ vagrant ssh -c 'sudo curl -o /etc/haproxy/haproxy.cfg https://gist.githubusercontent.com/nownabe/27ffdd8fed6a3f1707e8/raw/14d7f25fbd76c554c451610f2ac033bf809297bf/haproxy.cfg'
$ vagrant ssh -c 'sudo systemctl start haproxy'
以下、コンフィグの解説(抜粋)です。
# HAProxyのステータスをWebで見れるようにする設定です
listen hastats *:80
mode http
maxconn 64
timeout connect 5000
timeout client 10000
timeout server 10000
stats enable
stats show-legends
stats uri /haproxy?hastats
# ステータス画面のユーザ名とパスワードを設定しています
stats auth admin:p@ssw0rd
# MySQLの分散設定です
listen mysql *:3306
mode tcp
# mysql-checkという専用のヘルスチェック方式で、MySQLサーバに負荷をかけないようにしています
option mysql-check user haproxy
# ラウンドロビンでPXCの3ノードに分散します
balance roundrobin
server pxcnode-01 10.6.3.101 check
server pxcnode-02 10.6.3.102 check
server pxcnode-03 10.6.3.103 check
Railsアプリを作成する前に、ちゃんと負荷分散できてるか確認してみましょう。
次のコマンドでPXCから接続先のIPが取得できます。
$ vagrant ssh -c "mysql -udemo -h 127.0.0.1 -e 'show variables like \"wsrep_provider_options\"' | tail -1 | awk '{print \$4}'"
10.6.3.101;
$ vagrant ssh -c "mysql -udemo -h 127.0.0.1 -e 'show variables like \"wsrep_provider_options\"' | tail -1 | awk '{print \$4}'"
10.6.3.102;
$ vagrant ssh -c "mysql -udemo -h 127.0.0.1 -e 'show variables like \"wsrep_provider_options\"' | tail -1 | awk '{print \$4}'"
10.6.3.103;
$ vagrant ssh -c "mysql -udemo -h 127.0.0.1 -e 'show variables like \"wsrep_provider_options\"' | tail -1 | awk '{print \$4}'"
10.6.3.101;
ちゃんとラウンドロビンで分散されていることがわかります。
ブラウザでhttp://10.6.3.100/haproxy?hastats
にアクセスしてユーザとパスワードを入力すると、HAProxyのステータスが表示されます。
mysqlのSessionsのTotalを見ると、どのPXCノードに何回接続したかを確認できます。
4. Railsアプリ作成
では、Railsのアプリを作ります。
といってもPXCの動作確認が目的なのでScaffoldだけです。
ここからVMにSSHでログインして作業します。
$ vagrant ssh
まずはRailsアプリを作成しましょう。
$ rails new pxcdemo -d mysql -B
$ cd pxcdemo
$ echo "gem 'therubyracer', platform: :ruby" >> Gemfile
$ bundle install --path vendor/bundle
$ bundle exec rails g scaffold article title:string author:string body:text
config/database.yml
を書き換えます。
default: &default
adapter: mysql2
encoding: utf8
pool: 5
username: demo
password:
host: 127.0.0.1
development:
<<: *default
database: demo
Migrateしてサーバを起動します。
$ bundle exec rake db:migrate
$ bundle exec rails s -b 0.0.0.0
5. 動作確認
Railsのサーバが起動できたら、ブラウザでhttp://10.6.3.100:3000/articles
にアクセスして、適当にデータ入力してみてください。
HAProxyのステータス画面(http://10.6.3.100/haproxy?hastats
)にアクセスすると、接続数が増えてることがわかります。
こんな感じで、HAProxyを使うことで簡単にアプリからPercona XtraDB Clusterにアクセスすることができます。
HAProxyを各アプリケーションサーバに同居させることで、単一障害点を排除できます。
おわりに
長くなりましたが、以上です。
Percona XtraDB Clusterの構築方法と、アプリからの使用方法を書いてみました。
PXCを使うと本当に簡単に冗長化・負荷分散が実現できるので超おすすめです。
是非使ってみてください。