(2016年時点での内容をアーカイブとして掲載しているため、一部の掲載内容が最新情報とは異なる場合がありますので、ご了承ください。最新のIBM Cloudのアップデート情報はIBM Cloud アップデート情報 や 柔らか層本をご参照ください。)
概要
キープアライブ(Keepalived)をつかってLVSの高可用性(High Availability)構成をご紹介します。 LVSはウェブサーバー、KVS(Key-Value Store)、メモリキャッシュの負荷分散と高可用性のために、たいへん良く利用されています。 特にLVSは、データベースのアクセス負荷を軽減してレスポンスを改善するためにAPサーバーとDBサーバーの間で多く利用されています。 さらに、今回はMySQLのリード・レプリカを構成例を通してご紹介していきます。
LVSの高可用性構成
LVS (Linux Virtual Server)は、安価に構築できるのに高性能なロードバランサーとして、たいへん重宝されています。 このLVSをアクティブ・スタンバイ方式の高可用性の構成するために、キープアライブが利用されます。 SoftLayerでは、APサーバーとDBサーバー間など、プライベート・ネットワークの通信に対して、ローカル・ロードバランサーや高可用性の提供がありません。 しかし、LVSを利用することで、この課題を解決することができます。 LVSの概要説明は3.4 アクティブ・スタンバイのサーバーを構成するには?、シングル構成の設定方法は3.3 ロードバランサーを利用するには?をご参照お願いします。
次の図のLVSの左側のクライアントは、VIP(仮想IPアドレス)に向かってアクセスします。 そして、右側のサーバー群へ分散してアクセスします。 障害や保守のために、アクティブのLVSが停止した場合、スタンバイのLVSヘVIPが移動することで、クライアントは継続してVIPにアクセスして処理を継続することができます。 一方、LVSの右側にはMySQL, KVS, memcachedを配置して、応答を返せないサーバーへのアクセスを止めるために利用します。 次の図の中では、MySQLサーバーのリードレプリカに対する負荷分散の例です。
ウェブのよるカタログ販売の場合、そのほとんどが、カタログを閲覧しながら欲しい商品を探し求めるユーザーのアクセスとなり、商品データベースへの接続の殆どが、読取りアクセスとなります。 ここで快適な応答速度で表示ができなければ、ユーザーは去って行ってしまいます。 このため、MySQLの負荷分散は重要なテーマです。 KVSを使ってSQL文をキーとして結果をバリューに保管することで、MySQLの負荷を下げ、検索速度を劇的に改善する手法もありますが、ここでは、MySQLの読取り専用レプリカを複数準備してLVSで負荷分散する方法を例に挙げます。 この方法では、アプリケーションで、KVSをアクセスするためのコードを書かなくても良いため、実装が簡単になるメリットがあります。
VIPは、仮想サーバーや物理サーバーの起動時に付与されるIPアドレス以外のものを利用する必要があります。 クラウドの環境では、同じサブネットの空いているIPアドレスを適当にVIPとして使うと、IPアドレスは、クラウドの管理システムが割当を行なうため、新しく起動するサーバーのIPアドレスと同じになるといった障害になる恐れがあります。 そこで、SoftLayerでは、ポータブルIPという機能を活用します。 この機能の利用方法は、4.2 サーバーが変わっても同じIPアドレスを利用するには?をご参照お願いします。
構成に必要な材料の注文
具体的な構成では、次の図のようにLVSを一つのVLAN内だけで利用します。 LVSのVIPは、プライベート・アドレスを設定して、同じプライベートVLAN内のサーバーへ負荷分散することを実装していきます。
上記の構成を作るために、次の3点をカスタマーポータル ( https://control.softlayer.com/ )から注文します。
- 仮想サーバー CentOS 6.x - Minimal Install (64 bit) x 2 LVSのアクティブとスタンバイ
- 仮想サーバー CentOS 6.x - LAMP Install (64 bit) x 4 MySQLマスタ・サーバー x1, MySQLリード・レプリカ x2, アプリケーション・サーバー x1
- ポータブルIPアドレス(8 Portable Private IP Addresses)× 1 VIP用
LVS用として「仮想サーバー CentOS 6.x - Minimal Install (64 bit)」を注文します。 最初のサーバーの設定後に取得したイメージ・テンプレートから複製サーバーを起動して、アクティブ・スタンバイの設定を追加していきます。 MySQLのマスター、リード・レプリカ、ウェブサーバー用に「仮想サーバー CentOS 6.x - LAMP Install (64 bit)」を注文します。 「LAMP Install」は、Apache HTTP server、MySQL、PHPが最初から稼働できる状態でサーバーが起動してきます。 一方「Minimal Install」は、Linuxディストリビューションの最小限の導入になっています。
VIPのためのプライベートのポータブルIPアドレスは、無料ですので少し多めに、8個を確保しておきます。 この8個の内、3つはゲートウェイ、ネットワークアドレス、ブロードキャストアドレスとして、予約されていますので、5個を使うことができます。 ただし、プライベートの場合、SoftLayerのHSRPの予約アドレスが含まれることがあり、3個しか使えないことがあります。
これらの注文の方法は、仮想サーバーは1.2 仮想サーバーを起動するには?、ポータブルIPアドレスは4.2 サーバーが変わっても同じIPアドレスを利用するには?を参照してください。 そして、2台目のサーバーを作るには、「3.2.サーバーを複製するには?」の方法を利用していきます。 ここでは、判り易くするために、最初にまとめて注文するようにしていますが、仮想サーバーの費用を節約するには、必要な都度、注文する方法もあります。
LVSサーバーの追加ソフトウェアのインストール
仮想サーバーが起動したら、sshでログインして、KVSを設定を進めていきます。 仮想サーバーにログインする方法は、1.4 サーバーへログインするには?を参照してください。
仮想サーバーの起動直後は、OSの導入イメージ作成時点のソフトウェア更新レベルのため、現在までのアップデートを適用します。 これは以降の作業にとって重要なので必ず実施します。
# yum update
LVSのソフトウェアの導入を以下のコマンドで実行します。
# yum install ipvsadm keepalived
導入したサービスが、自動起動するように設定します。
# chkconfig ipvsadm on
# chkconfig keepalived on
複数のethインタフェース間でパケットの転送を許可するため /etc/sysctl.conf に、net.ipv4.ip_forward = 1 を設定します。
# vi /etc/sysctl.conf
# cat /etc/sysctl.conf
...省略
# Controls IP packet forwarding
net.ipv4.ip_forward = 1 <-- 1 へ変更する
編集した設定をカーネルに反映させるため、以下のコマンドを実行します。
# sysctl -p
LVSのアクティブ側設定
アクティブ・スタンバイの構成のため、キープアライブの /etc/keepalived/keepalived.conf を編集します。 変更箇所は「<--」で注釈しています。
[root@lvs1 ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
vrrp_instance vip_1 {
state MASTER <-- アクティブは「MASTER」、スタンバイは「BACKUP」と設定
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.66.136.58/32 dev eth0 <-- VIP と ネットワークインターフェース
}
}
virtual_server 10.66.136.58 3306 {
delay_loop 6
lb_algo wlc <-- 負荷分散アルゴリズムは、コネクション数と重み付けによる負荷分散
lb_kind DR <-- 転送方式は、ダイレクト・ルーティング
nat_mask 255.255.255.0
persistence_timeout 50
protocol TCP
real_server 10.67.24.196 3306 { <-- MySQL リードレプリカ #1
weight 1
TCP_CHECK {
connect_ip 10.67.24.196
connect_port 3306
}
}
real_server 10.67.24.198 3306 { <-- MySQL リードレプリカ #2
weight 1
TCP_CHECK {
connect_ip 10.67.24.198
connect_port 3306
}
}
}
これで、LVSのアクティブ側のキープアライブの設定が完了しました。 サービスを起動しておきます。
# service ipvsadm start
# service keepalived start
ここでスタンバイ側の設定は完了していませんが、以下のように、VIPが有効になっていることがわかります。
# ip addr show dev eth0
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 06:ac:64:68:be:bf brd ff:ff:ff:ff:ff:ff
inet 10.67.24.200/26 brd 10.67.24.255 scope global eth0 <-- 仮想サーバーのI/Fアドレス
inet 10.66.136.58/32 scope global eth0 <-- VIP
inet6 fe80::4ac:64ff:fe68:bebf/64 scope link
valid_lft forever preferred_lft forever
さらに、次のコマンドで、キープアライブの設定ファイルの内容が、IPVS(IP Virtual Server: ロードバランサ機能を持つLVSの構成要素)に反映されていることが確認できます。
[root@lvs1 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.66.136.58:3306 wlc persistent 50
-> 10.67.24.196:3306 Route 1 0 0
-> 10.67.24.198:3306 Route 1 0 0
LVS用の仮想サーバーの複製
ここまで作成してきた仮想サーバーをマスターのイメージにして、スタンバイになるサーバーを作成します。 この作成方法は、3.2 サーバーのクローンを作成するには?を参照してください。 イメージから新たなサーバーを起動する場合、元の仮想サーバーと同じVLANに作成する必要があります。 この理由は、VIPを利用するポータブルIPはVLANに割当られるためです。 新たに起動される仮想サーバーのIPアドレスは、異なるアドレスが付与され、ホスト名は起動時に指定したものが付与されます。
複製されたサーバーのIPアドレスのサブネットは、元になったサーバーと異なるサブネットに割り当てられる可能性がありますが、VLANが同じであれば、ポータブルIPを利用することに問題はありません。
LVSのスタンバイ側設定
イメージ・テンプレートから起動した仮想サーバーの /etc/keepalived/keepalived.conf の次の部分を「BACKUP」に値を変更します。
# vi /etc/keepalived/keepalived.conf
...省略
vrrp_instance vip_1 {
state MASTER <-- スタンバイは「BACKUP」と設定
interface eth0
...省略
これで、LVSのスタンバイの設定が完了しましたので、サービスを起動します。
# service ipvsadm start
# service keepalived start
これで、LVSのアクティブ・スタンバイの設定が完了しました。 次に、LVSが負荷分散するMySQLのリードレプリカの設定に移っていきます。 ここで、次に説明する設定を行なわないで、VIPをアクセスして振り分けの確認をしてはいけません。 少しだけ我慢をお願いします。
MySQLのリードレプリカの設定 (LVSのリアルサーバー設定)
LVSがリクエストを振分け先は、同じプライベートIP側のMySQLリードレプリカのサーバーに転送するために、少し特別な設定が必要になります。 LVSのVIPに届いたパケットをダイレクトに転送するため、転送先のサーバーがパケットを自分のパケットとして受け取るように、ifcfg-lo:0ファイルを作成して、VIPアドレスを設定します。
[root@db2 ~]# cat /etc/sysconfig/network-scripts/ifcfg-lo:1
DEVICE=lo:1
IPADDR=10.66.136.58 <-- VIPのアドレス
NETMASK=255.255.255.255
ONBOOT=yes
NAME=loopback
次の設定は、大変重要な設定で省略するとLVSが期待通りに動作しません。 イーサーネットでは、ARPによって、IPパケットの次の転送先を記憶する機能があります。 もし間違った値を周辺のルーターが記憶していまうと、キャッシュがリフレッシュされるまで、正しく通信できない状態になります。 次の設定は、この問題を回避するために、LVSの振り分け先のサーバーでARPを無視、また、通知しないというものです。 もしこの設定をしないで動かしてしまうと、LVSから来たパケットを処理する過程で、SoftLayer側のルーターへ、MySQLレプリカのサーバーである自己のMACアドレスが、VIPの代表アドレスとしてARPで通知します。 そうすると、それ以降は、VIPの転送先は、LVSではなくMySQLサーバー側に固定され、LVSをバイパスされ負荷分散が働かなくなります。
/etc/sysctl.confのファイルに次の4行を追加します。
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
カーネルへ設定を反映させるためsysctlコマンドを実行します。
# sysctl -p
ループバック・インターフェースを有効にします。
# ifup lo:1
MySQLのマスターサーバーの設定
リードレプリカへ更新ログを提供するためのMySQLサーバーを設定した後、リードレプリカのMySQLサーバーを設定します。
# cat /etc/my.cnf
[mysqld]
server-id=100 <-- 複数のMySQLサーバーを連携させるため、識別子を設定
log-bin=log-bin <-- バイナリ形式のログを出力するように設定
character-set-server = utf8
collation-server = utf8_general_ci
...省略
設定を保存してMySQLサービスを開始します。 また、サーバーが再起動しても自動起動するように設定しておきます。
# service mysqld start
# chkconfig mysqld on
次のコマンドで、MySQLサーバーにログインして、レプリカサーバーの登録、レプリカへのデータ転送を進めていきます。
# mysql
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 38
Server version: 5.1.73-log Source distribution
リード・レプリカのユーザー、IPアドレス、パスワードを登録します。 負荷分散するリード・レプリカのサーバー数分だけ登録します。
mysql> GRANT REPLICATION SLAVE ON *.* TO repl@10.67.24.196 IDENTIFIED BY 'Passw0rd';
Query OK, 0 rows affected (0.00 sec)
データを転送する前に、バッファを書き出してロックします。
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
ログファイルの名前とポジションは、レプリカ側で開始前に設定する必要があるので、メモしておきます。
mysql> SHOW MASTER STATUS;
+----------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+----------------+----------+--------------+------------------+
| log-bin.000003 | 257 | | |
+----------------+----------+--------------+------------------+
1 row in set (0.00 sec)
MySQLのデータ領域を丸ごとレプリカ側へ転送します。 そして、他のすべてのレプリカ・サーバーへもコピーを実行します。
# cd /var/lib/mysql
# scp -r * 10.67.24.196:/var/lib/mysql
次のコマンドで、ロックを解除して、マスター側の設定は完了です。
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
MySQLのリードレプリカの設定
設定ファイルの変更します。 レプリカでは、バイナリーログの出力設定は不要です。
# cat /etc/my.cnf
[mysqld]
server-id=101 <-- 他のサーバーと異なる一意の識別子を設定
character-set-server = utf8
collation-server = utf8_general_ci
...省略
コピーしたファイルは、オーナーを変更して、MySQLサーバーを起動します。 次回から自動起動にします。
# chown -R mysql:mysql /var/lib/mysql/
# service mysqld start
Starting mysqld: [ OK ]
# chkconfig mysqld on
マスター側で、コピー前にロックしていたので、解除します。
mysql> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
マスター側で取得したファイル名とポジションを設定します。
mysql > CHANGE MASTER TO MASTER_HOST='10.67.24.201',MASTER_USER='repl',MASTER_PASSWORD='Passw0rd',
MASTER_LOG_FILE='log-bin.000003',MASTER_LOG_POS=257;
次のコマンドで、レプリカを開始します。
mysql> START SLAVE;
マスターとリードレプリカの連携状態を確認します。 ここで問題が発見された場合、最初から手順を見直します。
mysql> show slave status G
...省略
Slave_IO_Running: Yes <-- YESであれば成功
Slave_SQL_Running: Yes <-- 同上
...省略
Last_IO_Errno: 0
Last_IO_Error: <-- 上記がNOになる原因のメッセージが表示される
Last_SQL_Errno: 0
Last_SQL_Error: <-- 同上
1 row in set (0.00 sec)
おめでどうございます! これでマスターとレプリケーションの設定が完了です。
動作確認
アプリケーションサーバーからVIPをアクセスして、MySQLのリードレプリカをアクセスして、動作確認を行います。
最初にマスターのMySQLで、テーブルを作ってデータを登録しておきます。 ここで登録したデータがリード・レプリカのMySQLサーバーから読み取ることで、レプリカ設定を確認します。
mysql> use test;
Database changed
mysql> create table person (id int, name varchar(20));
Query OK, 0 rows affected (0.01 sec)
mysql> insert into person (id,name) values (1, 'takara');
Query OK, 1 row affected (0.00 sec)
mysql> insert into person (id,name) values (2, 'suzuki');
Query OK, 1 row affected (0.00 sec)
マスター側とレプリカ側で、それぞれ SELECT を実行して、同じ結果が得られることを確認します。
# mysql
...省略
mysql> select id,name from person;
+------+--------+
| id | name |
+------+--------+
| 1 | takara |
| 2 | suzuki |
+------+--------+
2 rows in set (0.00 sec)
次に、アプリケーション・サーバーから、VIPを指定して mysql コマンドを実行して、接続を確認します。 その前に、外部のサーバーからアクセスできるようにするための、設定を行ないます。 次のコマンドは、アプリケーション・サーバーのIPアドレスから、root ユーザーが指定のパスワードで、アクセスを許可するものです。 VIPを介してアクセスするアプリケーション・サーバーについて、アクセスできるように設定しておく必要あります。
mysql> grant all on *.* to 'root'@'10.67.24.194' IDENTIFIED BY 'Passw0rd';
この設定により、アプリケーション・サーバーから mysql コマンドを実行できるようになったので、確認します。
[root@web1 html]# mysql -u root -h 10.66.136.58 test -p
Enter password:
...省略
mysql>
LVSのアクティブ側のサーバーにログインして、次のコマンドを実行することで、VIPから転送されている状況を確認することができます。
[root@lvs1 ~]# ipvsadm -Lnc
IPVS connection entries
pro expire state source virtual destination
TCP 00:12 NONE 10.67.24.194:0 10.66.136.58:3306 10.67.24.198:3306
TCP 14:22 ESTABLISHED 10.67.24.194:45782 10.66.136.58:3306 10.67.24.198:3306
それでは、PHPのアプリケーションからの動作確認です。 次のテスト用コードを /var/httpd/html において、ブラウザからアクセスします。
# cat index.php
接続に成功しました。
');
$db_selected = mysql_select_db('test', $link);
if (!$db_selected){
die('データベース選択失敗です。'.mysql_error());
}
print('
testデータベースを選択しました。
');
mysql_set_charset('utf8');
$result = mysql_query('SELECT id,name FROM person ORDER BY id');
if (!$result) {
die('クエリーが失敗しました。'.mysql_error());
}
while ($row = mysql_fetch_assoc($result)) {
print('id='.$row['id']);
print(',name='.$row['name']);
print('
');
}
$close_flag = mysql_close($link);
if ($close_flag){
print('
切断に成功しました。
');
}
?>
次のブラウザ画面のように表示されたら成功です。 マスターMySQLでデータを適当に追加して、レプリカ側へ反映されていることが確認できます。
これで、HA構成の動作確認として、MySQLサーバーのリード・レプリカの一つを停止、また、LVSのプライマリを停止させても、ブラウザからのアクセスが継続できることが確認できます。 いろいろ試してみて構成の理解を深めて頂けると幸いです。
まとめ
本章では、プライベート・ネットワークに負荷分散サーバーとして LVS をHA構成で立ち上げ、ウェブ・アプリケーションサーバーが、VIPを経由して、MySQLのリード・レプリカサーバーへアクセスする方法を見てきました。 この方法は、KVSにも適用でき、たいへん応用価値の高い構成です。 設定の手間はかかりますが、システム内部の連携に関して、最小の仮想サーバーでも構成できるためコストパフォーマンスが良く、高可用性の構成が可能であることを、ご理解頂けたのはないかと思います。